]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Merge pull request #3268 from tomhughes/capitalisation
[rails.git] / vendor / assets / iD / iD.js
1 (function () {
2
3         var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
4
5         function createCommonjsModule(fn) {
6           var module = { exports: {} };
7                 return fn(module, module.exports), module.exports;
8         }
9
10         var check = function (it) {
11           return it && it.Math == Math && it;
12         };
13
14         // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
15         var global$2 =
16           // eslint-disable-next-line es/no-global-this -- safe
17           check(typeof globalThis == 'object' && globalThis) ||
18           check(typeof window == 'object' && window) ||
19           // eslint-disable-next-line no-restricted-globals -- safe
20           check(typeof self == 'object' && self) ||
21           check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
22           // eslint-disable-next-line no-new-func -- fallback
23           (function () { return this; })() || Function('return this')();
24
25         var fails = function (exec) {
26           try {
27             return !!exec();
28           } catch (error) {
29             return true;
30           }
31         };
32
33         // Detect IE8's incomplete defineProperty implementation
34         var descriptors = !fails(function () {
35           // eslint-disable-next-line es/no-object-defineproperty -- required for testing
36           return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;
37         });
38
39         var $propertyIsEnumerable$1 = {}.propertyIsEnumerable;
40         // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
41         var getOwnPropertyDescriptor$5 = Object.getOwnPropertyDescriptor;
42
43         // Nashorn ~ JDK8 bug
44         var NASHORN_BUG = getOwnPropertyDescriptor$5 && !$propertyIsEnumerable$1.call({ 1: 2 }, 1);
45
46         // `Object.prototype.propertyIsEnumerable` method implementation
47         // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
48         var f$7 = NASHORN_BUG ? function propertyIsEnumerable(V) {
49           var descriptor = getOwnPropertyDescriptor$5(this, V);
50           return !!descriptor && descriptor.enumerable;
51         } : $propertyIsEnumerable$1;
52
53         var objectPropertyIsEnumerable = {
54                 f: f$7
55         };
56
57         var createPropertyDescriptor = function (bitmap, value) {
58           return {
59             enumerable: !(bitmap & 1),
60             configurable: !(bitmap & 2),
61             writable: !(bitmap & 4),
62             value: value
63           };
64         };
65
66         var toString$1 = {}.toString;
67
68         var classofRaw = function (it) {
69           return toString$1.call(it).slice(8, -1);
70         };
71
72         var split$2 = ''.split;
73
74         // fallback for non-array-like ES3 and non-enumerable old V8 strings
75         var indexedObject = fails(function () {
76           // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
77           // eslint-disable-next-line no-prototype-builtins -- safe
78           return !Object('z').propertyIsEnumerable(0);
79         }) ? function (it) {
80           return classofRaw(it) == 'String' ? split$2.call(it, '') : Object(it);
81         } : Object;
82
83         // `RequireObjectCoercible` abstract operation
84         // https://tc39.es/ecma262/#sec-requireobjectcoercible
85         var requireObjectCoercible = function (it) {
86           if (it == undefined) throw TypeError("Can't call method on " + it);
87           return it;
88         };
89
90         // toObject with fallback for non-array-like ES3 strings
91
92
93
94         var toIndexedObject = function (it) {
95           return indexedObject(requireObjectCoercible(it));
96         };
97
98         var isObject$4 = function (it) {
99           return typeof it === 'object' ? it !== null : typeof it === 'function';
100         };
101
102         // `ToPrimitive` abstract operation
103         // https://tc39.es/ecma262/#sec-toprimitive
104         // instead of the ES6 spec version, we didn't implement @@toPrimitive case
105         // and the second argument - flag - preferred type is a string
106         var toPrimitive = function (input, PREFERRED_STRING) {
107           if (!isObject$4(input)) return input;
108           var fn, val;
109           if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject$4(val = fn.call(input))) return val;
110           if (typeof (fn = input.valueOf) == 'function' && !isObject$4(val = fn.call(input))) return val;
111           if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject$4(val = fn.call(input))) return val;
112           throw TypeError("Can't convert object to primitive value");
113         };
114
115         // `ToObject` abstract operation
116         // https://tc39.es/ecma262/#sec-toobject
117         var toObject = function (argument) {
118           return Object(requireObjectCoercible(argument));
119         };
120
121         var hasOwnProperty$3 = {}.hasOwnProperty;
122
123         var has$1 = Object.hasOwn || function hasOwn(it, key) {
124           return hasOwnProperty$3.call(toObject(it), key);
125         };
126
127         var document$3 = global$2.document;
128         // typeof document.createElement is 'object' in old IE
129         var EXISTS = isObject$4(document$3) && isObject$4(document$3.createElement);
130
131         var documentCreateElement = function (it) {
132           return EXISTS ? document$3.createElement(it) : {};
133         };
134
135         // Thank's IE8 for his funny defineProperty
136         var ie8DomDefine = !descriptors && !fails(function () {
137           // eslint-disable-next-line es/no-object-defineproperty -- requied for testing
138           return Object.defineProperty(documentCreateElement('div'), 'a', {
139             get: function () { return 7; }
140           }).a != 7;
141         });
142
143         // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
144         var $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
145
146         // `Object.getOwnPropertyDescriptor` method
147         // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
148         var f$6 = descriptors ? $getOwnPropertyDescriptor$1 : function getOwnPropertyDescriptor(O, P) {
149           O = toIndexedObject(O);
150           P = toPrimitive(P, true);
151           if (ie8DomDefine) try {
152             return $getOwnPropertyDescriptor$1(O, P);
153           } catch (error) { /* empty */ }
154           if (has$1(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
155         };
156
157         var objectGetOwnPropertyDescriptor = {
158                 f: f$6
159         };
160
161         var anObject = function (it) {
162           if (!isObject$4(it)) {
163             throw TypeError(String(it) + ' is not an object');
164           } return it;
165         };
166
167         // eslint-disable-next-line es/no-object-defineproperty -- safe
168         var $defineProperty$1 = Object.defineProperty;
169
170         // `Object.defineProperty` method
171         // https://tc39.es/ecma262/#sec-object.defineproperty
172         var f$5 = descriptors ? $defineProperty$1 : function defineProperty(O, P, Attributes) {
173           anObject(O);
174           P = toPrimitive(P, true);
175           anObject(Attributes);
176           if (ie8DomDefine) try {
177             return $defineProperty$1(O, P, Attributes);
178           } catch (error) { /* empty */ }
179           if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
180           if ('value' in Attributes) O[P] = Attributes.value;
181           return O;
182         };
183
184         var objectDefineProperty = {
185                 f: f$5
186         };
187
188         var createNonEnumerableProperty = descriptors ? function (object, key, value) {
189           return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
190         } : function (object, key, value) {
191           object[key] = value;
192           return object;
193         };
194
195         var setGlobal = function (key, value) {
196           try {
197             createNonEnumerableProperty(global$2, key, value);
198           } catch (error) {
199             global$2[key] = value;
200           } return value;
201         };
202
203         var SHARED = '__core-js_shared__';
204         var store$1 = global$2[SHARED] || setGlobal(SHARED, {});
205
206         var sharedStore = store$1;
207
208         var functionToString = Function.toString;
209
210         // this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper
211         if (typeof sharedStore.inspectSource != 'function') {
212           sharedStore.inspectSource = function (it) {
213             return functionToString.call(it);
214           };
215         }
216
217         var inspectSource = sharedStore.inspectSource;
218
219         var WeakMap$1 = global$2.WeakMap;
220
221         var nativeWeakMap = typeof WeakMap$1 === 'function' && /native code/.test(inspectSource(WeakMap$1));
222
223         var isPure = false;
224
225         var shared = createCommonjsModule(function (module) {
226         (module.exports = function (key, value) {
227           return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
228         })('versions', []).push({
229           version: '3.15.2',
230           mode: 'global',
231           copyright: '© 2021 Denis Pushkarev (zloirock.ru)'
232         });
233         });
234
235         var id$1 = 0;
236         var postfix = Math.random();
237
238         var uid = function (key) {
239           return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id$1 + postfix).toString(36);
240         };
241
242         var keys$3 = shared('keys');
243
244         var sharedKey = function (key) {
245           return keys$3[key] || (keys$3[key] = uid(key));
246         };
247
248         var hiddenKeys$1 = {};
249
250         var OBJECT_ALREADY_INITIALIZED = 'Object already initialized';
251         var WeakMap = global$2.WeakMap;
252         var set$4, get$5, has;
253
254         var enforce = function (it) {
255           return has(it) ? get$5(it) : set$4(it, {});
256         };
257
258         var getterFor = function (TYPE) {
259           return function (it) {
260             var state;
261             if (!isObject$4(it) || (state = get$5(it)).type !== TYPE) {
262               throw TypeError('Incompatible receiver, ' + TYPE + ' required');
263             } return state;
264           };
265         };
266
267         if (nativeWeakMap || sharedStore.state) {
268           var store = sharedStore.state || (sharedStore.state = new WeakMap());
269           var wmget = store.get;
270           var wmhas = store.has;
271           var wmset = store.set;
272           set$4 = function (it, metadata) {
273             if (wmhas.call(store, it)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
274             metadata.facade = it;
275             wmset.call(store, it, metadata);
276             return metadata;
277           };
278           get$5 = function (it) {
279             return wmget.call(store, it) || {};
280           };
281           has = function (it) {
282             return wmhas.call(store, it);
283           };
284         } else {
285           var STATE = sharedKey('state');
286           hiddenKeys$1[STATE] = true;
287           set$4 = function (it, metadata) {
288             if (has$1(it, STATE)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
289             metadata.facade = it;
290             createNonEnumerableProperty(it, STATE, metadata);
291             return metadata;
292           };
293           get$5 = function (it) {
294             return has$1(it, STATE) ? it[STATE] : {};
295           };
296           has = function (it) {
297             return has$1(it, STATE);
298           };
299         }
300
301         var internalState = {
302           set: set$4,
303           get: get$5,
304           has: has,
305           enforce: enforce,
306           getterFor: getterFor
307         };
308
309         var redefine = createCommonjsModule(function (module) {
310         var getInternalState = internalState.get;
311         var enforceInternalState = internalState.enforce;
312         var TEMPLATE = String(String).split('String');
313
314         (module.exports = function (O, key, value, options) {
315           var unsafe = options ? !!options.unsafe : false;
316           var simple = options ? !!options.enumerable : false;
317           var noTargetGet = options ? !!options.noTargetGet : false;
318           var state;
319           if (typeof value == 'function') {
320             if (typeof key == 'string' && !has$1(value, 'name')) {
321               createNonEnumerableProperty(value, 'name', key);
322             }
323             state = enforceInternalState(value);
324             if (!state.source) {
325               state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
326             }
327           }
328           if (O === global$2) {
329             if (simple) O[key] = value;
330             else setGlobal(key, value);
331             return;
332           } else if (!unsafe) {
333             delete O[key];
334           } else if (!noTargetGet && O[key]) {
335             simple = true;
336           }
337           if (simple) O[key] = value;
338           else createNonEnumerableProperty(O, key, value);
339         // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
340         })(Function.prototype, 'toString', function toString() {
341           return typeof this == 'function' && getInternalState(this).source || inspectSource(this);
342         });
343         });
344
345         var path = global$2;
346
347         var aFunction$1 = function (variable) {
348           return typeof variable == 'function' ? variable : undefined;
349         };
350
351         var getBuiltIn = function (namespace, method) {
352           return arguments.length < 2 ? aFunction$1(path[namespace]) || aFunction$1(global$2[namespace])
353             : path[namespace] && path[namespace][method] || global$2[namespace] && global$2[namespace][method];
354         };
355
356         var ceil$1 = Math.ceil;
357         var floor$7 = Math.floor;
358
359         // `ToInteger` abstract operation
360         // https://tc39.es/ecma262/#sec-tointeger
361         var toInteger = function (argument) {
362           return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor$7 : ceil$1)(argument);
363         };
364
365         var min$9 = Math.min;
366
367         // `ToLength` abstract operation
368         // https://tc39.es/ecma262/#sec-tolength
369         var toLength = function (argument) {
370           return argument > 0 ? min$9(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
371         };
372
373         var max$4 = Math.max;
374         var min$8 = Math.min;
375
376         // Helper for a popular repeating case of the spec:
377         // Let integer be ? ToInteger(index).
378         // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
379         var toAbsoluteIndex = function (index, length) {
380           var integer = toInteger(index);
381           return integer < 0 ? max$4(integer + length, 0) : min$8(integer, length);
382         };
383
384         // `Array.prototype.{ indexOf, includes }` methods implementation
385         var createMethod$6 = function (IS_INCLUDES) {
386           return function ($this, el, fromIndex) {
387             var O = toIndexedObject($this);
388             var length = toLength(O.length);
389             var index = toAbsoluteIndex(fromIndex, length);
390             var value;
391             // Array#includes uses SameValueZero equality algorithm
392             // eslint-disable-next-line no-self-compare -- NaN check
393             if (IS_INCLUDES && el != el) while (length > index) {
394               value = O[index++];
395               // eslint-disable-next-line no-self-compare -- NaN check
396               if (value != value) return true;
397             // Array#indexOf ignores holes, Array#includes - not
398             } else for (;length > index; index++) {
399               if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
400             } return !IS_INCLUDES && -1;
401           };
402         };
403
404         var arrayIncludes = {
405           // `Array.prototype.includes` method
406           // https://tc39.es/ecma262/#sec-array.prototype.includes
407           includes: createMethod$6(true),
408           // `Array.prototype.indexOf` method
409           // https://tc39.es/ecma262/#sec-array.prototype.indexof
410           indexOf: createMethod$6(false)
411         };
412
413         var indexOf = arrayIncludes.indexOf;
414
415
416         var objectKeysInternal = function (object, names) {
417           var O = toIndexedObject(object);
418           var i = 0;
419           var result = [];
420           var key;
421           for (key in O) !has$1(hiddenKeys$1, key) && has$1(O, key) && result.push(key);
422           // Don't enum bug & hidden keys
423           while (names.length > i) if (has$1(O, key = names[i++])) {
424             ~indexOf(result, key) || result.push(key);
425           }
426           return result;
427         };
428
429         // IE8- don't enum bug keys
430         var enumBugKeys = [
431           'constructor',
432           'hasOwnProperty',
433           'isPrototypeOf',
434           'propertyIsEnumerable',
435           'toLocaleString',
436           'toString',
437           'valueOf'
438         ];
439
440         var hiddenKeys = enumBugKeys.concat('length', 'prototype');
441
442         // `Object.getOwnPropertyNames` method
443         // https://tc39.es/ecma262/#sec-object.getownpropertynames
444         // eslint-disable-next-line es/no-object-getownpropertynames -- safe
445         var f$4 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
446           return objectKeysInternal(O, hiddenKeys);
447         };
448
449         var objectGetOwnPropertyNames = {
450                 f: f$4
451         };
452
453         // eslint-disable-next-line es/no-object-getownpropertysymbols -- safe
454         var f$3 = Object.getOwnPropertySymbols;
455
456         var objectGetOwnPropertySymbols = {
457                 f: f$3
458         };
459
460         // all object keys, includes non-enumerable and symbols
461         var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
462           var keys = objectGetOwnPropertyNames.f(anObject(it));
463           var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
464           return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
465         };
466
467         var copyConstructorProperties = function (target, source) {
468           var keys = ownKeys(source);
469           var defineProperty = objectDefineProperty.f;
470           var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
471           for (var i = 0; i < keys.length; i++) {
472             var key = keys[i];
473             if (!has$1(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
474           }
475         };
476
477         var replacement = /#|\.prototype\./;
478
479         var isForced = function (feature, detection) {
480           var value = data[normalize$1(feature)];
481           return value == POLYFILL ? true
482             : value == NATIVE ? false
483             : typeof detection == 'function' ? fails(detection)
484             : !!detection;
485         };
486
487         var normalize$1 = isForced.normalize = function (string) {
488           return String(string).replace(replacement, '.').toLowerCase();
489         };
490
491         var data = isForced.data = {};
492         var NATIVE = isForced.NATIVE = 'N';
493         var POLYFILL = isForced.POLYFILL = 'P';
494
495         var isForced_1 = isForced;
496
497         var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;
498
499
500
501
502
503
504         /*
505           options.target      - name of the target object
506           options.global      - target is the global object
507           options.stat        - export as static methods of target
508           options.proto       - export as prototype methods of target
509           options.real        - real prototype method for the `pure` version
510           options.forced      - export even if the native feature is available
511           options.bind        - bind methods to the target, required for the `pure` version
512           options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
513           options.unsafe      - use the simple assignment of property instead of delete + defineProperty
514           options.sham        - add a flag to not completely full polyfills
515           options.enumerable  - export as enumerable property
516           options.noTargetGet - prevent calling a getter on target
517         */
518         var _export = function (options, source) {
519           var TARGET = options.target;
520           var GLOBAL = options.global;
521           var STATIC = options.stat;
522           var FORCED, target, key, targetProperty, sourceProperty, descriptor;
523           if (GLOBAL) {
524             target = global$2;
525           } else if (STATIC) {
526             target = global$2[TARGET] || setGlobal(TARGET, {});
527           } else {
528             target = (global$2[TARGET] || {}).prototype;
529           }
530           if (target) for (key in source) {
531             sourceProperty = source[key];
532             if (options.noTargetGet) {
533               descriptor = getOwnPropertyDescriptor$4(target, key);
534               targetProperty = descriptor && descriptor.value;
535             } else targetProperty = target[key];
536             FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
537             // contained in target
538             if (!FORCED && targetProperty !== undefined) {
539               if (typeof sourceProperty === typeof targetProperty) continue;
540               copyConstructorProperties(sourceProperty, targetProperty);
541             }
542             // add a flag to not completely full polyfills
543             if (options.sham || (targetProperty && targetProperty.sham)) {
544               createNonEnumerableProperty(sourceProperty, 'sham', true);
545             }
546             // extend global
547             redefine(target, key, sourceProperty, options);
548           }
549         };
550
551         // `Date.now` method
552         // https://tc39.es/ecma262/#sec-date.now
553         _export({ target: 'Date', stat: true }, {
554           now: function now() {
555             return new Date().getTime();
556           }
557         });
558
559         var DatePrototype$1 = Date.prototype;
560         var INVALID_DATE = 'Invalid Date';
561         var TO_STRING$1 = 'toString';
562         var nativeDateToString = DatePrototype$1[TO_STRING$1];
563         var getTime$1 = DatePrototype$1.getTime;
564
565         // `Date.prototype.toString` method
566         // https://tc39.es/ecma262/#sec-date.prototype.tostring
567         if (new Date(NaN) + '' != INVALID_DATE) {
568           redefine(DatePrototype$1, TO_STRING$1, function toString() {
569             var value = getTime$1.call(this);
570             // eslint-disable-next-line no-self-compare -- NaN check
571             return value === value ? nativeDateToString.call(this) : INVALID_DATE;
572           });
573         }
574
575         function _typeof(obj) {
576           "@babel/helpers - typeof";
577
578           if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
579             _typeof = function (obj) {
580               return typeof obj;
581             };
582           } else {
583             _typeof = function (obj) {
584               return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
585             };
586           }
587
588           return _typeof(obj);
589         }
590
591         function _classCallCheck$1(instance, Constructor) {
592           if (!(instance instanceof Constructor)) {
593             throw new TypeError("Cannot call a class as a function");
594           }
595         }
596
597         function _defineProperties$1(target, props) {
598           for (var i = 0; i < props.length; i++) {
599             var descriptor = props[i];
600             descriptor.enumerable = descriptor.enumerable || false;
601             descriptor.configurable = true;
602             if ("value" in descriptor) descriptor.writable = true;
603             Object.defineProperty(target, descriptor.key, descriptor);
604           }
605         }
606
607         function _createClass$1(Constructor, protoProps, staticProps) {
608           if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
609           if (staticProps) _defineProperties$1(Constructor, staticProps);
610           return Constructor;
611         }
612
613         function _defineProperty(obj, key, value) {
614           if (key in obj) {
615             Object.defineProperty(obj, key, {
616               value: value,
617               enumerable: true,
618               configurable: true,
619               writable: true
620             });
621           } else {
622             obj[key] = value;
623           }
624
625           return obj;
626         }
627
628         function _slicedToArray(arr, i) {
629           return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
630         }
631
632         function _toConsumableArray(arr) {
633           return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
634         }
635
636         function _arrayWithoutHoles(arr) {
637           if (Array.isArray(arr)) return _arrayLikeToArray(arr);
638         }
639
640         function _arrayWithHoles(arr) {
641           if (Array.isArray(arr)) return arr;
642         }
643
644         function _iterableToArray(iter) {
645           if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
646         }
647
648         function _iterableToArrayLimit(arr, i) {
649           var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
650
651           if (_i == null) return;
652           var _arr = [];
653           var _n = true;
654           var _d = false;
655
656           var _s, _e;
657
658           try {
659             for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
660               _arr.push(_s.value);
661
662               if (i && _arr.length === i) break;
663             }
664           } catch (err) {
665             _d = true;
666             _e = err;
667           } finally {
668             try {
669               if (!_n && _i["return"] != null) _i["return"]();
670             } finally {
671               if (_d) throw _e;
672             }
673           }
674
675           return _arr;
676         }
677
678         function _unsupportedIterableToArray(o, minLen) {
679           if (!o) return;
680           if (typeof o === "string") return _arrayLikeToArray(o, minLen);
681           var n = Object.prototype.toString.call(o).slice(8, -1);
682           if (n === "Object" && o.constructor) n = o.constructor.name;
683           if (n === "Map" || n === "Set") return Array.from(o);
684           if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
685         }
686
687         function _arrayLikeToArray(arr, len) {
688           if (len == null || len > arr.length) len = arr.length;
689
690           for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
691
692           return arr2;
693         }
694
695         function _nonIterableSpread() {
696           throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
697         }
698
699         function _nonIterableRest() {
700           throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
701         }
702
703         function _createForOfIteratorHelper(o, allowArrayLike) {
704           var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
705
706           if (!it) {
707             if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
708               if (it) o = it;
709               var i = 0;
710
711               var F = function () {};
712
713               return {
714                 s: F,
715                 n: function () {
716                   if (i >= o.length) return {
717                     done: true
718                   };
719                   return {
720                     done: false,
721                     value: o[i++]
722                   };
723                 },
724                 e: function (e) {
725                   throw e;
726                 },
727                 f: F
728               };
729             }
730
731             throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
732           }
733
734           var normalCompletion = true,
735               didErr = false,
736               err;
737           return {
738             s: function () {
739               it = it.call(o);
740             },
741             n: function () {
742               var step = it.next();
743               normalCompletion = step.done;
744               return step;
745             },
746             e: function (e) {
747               didErr = true;
748               err = e;
749             },
750             f: function () {
751               try {
752                 if (!normalCompletion && it.return != null) it.return();
753               } finally {
754                 if (didErr) throw err;
755               }
756             }
757           };
758         }
759
760         var engineUserAgent = getBuiltIn('navigator', 'userAgent') || '';
761
762         var process$4 = global$2.process;
763         var versions = process$4 && process$4.versions;
764         var v8 = versions && versions.v8;
765         var match, version$1;
766
767         if (v8) {
768           match = v8.split('.');
769           version$1 = match[0] < 4 ? 1 : match[0] + match[1];
770         } else if (engineUserAgent) {
771           match = engineUserAgent.match(/Edge\/(\d+)/);
772           if (!match || match[1] >= 74) {
773             match = engineUserAgent.match(/Chrome\/(\d+)/);
774             if (match) version$1 = match[1];
775           }
776         }
777
778         var engineV8Version = version$1 && +version$1;
779
780         /* eslint-disable es/no-symbol -- required for testing */
781
782         // eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
783         var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
784           var symbol = Symbol();
785           // Chrome 38 Symbol has incorrect toString conversion
786           // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
787           return !String(symbol) || !(Object(symbol) instanceof Symbol) ||
788             // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
789             !Symbol.sham && engineV8Version && engineV8Version < 41;
790         });
791
792         /* eslint-disable es/no-symbol -- required for testing */
793
794         var useSymbolAsUid = nativeSymbol
795           && !Symbol.sham
796           && typeof Symbol.iterator == 'symbol';
797
798         var WellKnownSymbolsStore$1 = shared('wks');
799         var Symbol$1 = global$2.Symbol;
800         var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid;
801
802         var wellKnownSymbol = function (name) {
803           if (!has$1(WellKnownSymbolsStore$1, name) || !(nativeSymbol || typeof WellKnownSymbolsStore$1[name] == 'string')) {
804             if (nativeSymbol && has$1(Symbol$1, name)) {
805               WellKnownSymbolsStore$1[name] = Symbol$1[name];
806             } else {
807               WellKnownSymbolsStore$1[name] = createWellKnownSymbol('Symbol.' + name);
808             }
809           } return WellKnownSymbolsStore$1[name];
810         };
811
812         var f$2 = wellKnownSymbol;
813
814         var wellKnownSymbolWrapped = {
815                 f: f$2
816         };
817
818         var defineProperty$9 = objectDefineProperty.f;
819
820         var defineWellKnownSymbol = function (NAME) {
821           var Symbol = path.Symbol || (path.Symbol = {});
822           if (!has$1(Symbol, NAME)) defineProperty$9(Symbol, NAME, {
823             value: wellKnownSymbolWrapped.f(NAME)
824           });
825         };
826
827         // `Symbol.iterator` well-known symbol
828         // https://tc39.es/ecma262/#sec-symbol.iterator
829         defineWellKnownSymbol('iterator');
830
831         // `Object.keys` method
832         // https://tc39.es/ecma262/#sec-object.keys
833         // eslint-disable-next-line es/no-object-keys -- safe
834         var objectKeys = Object.keys || function keys(O) {
835           return objectKeysInternal(O, enumBugKeys);
836         };
837
838         // `Object.defineProperties` method
839         // https://tc39.es/ecma262/#sec-object.defineproperties
840         // eslint-disable-next-line es/no-object-defineproperties -- safe
841         var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
842           anObject(O);
843           var keys = objectKeys(Properties);
844           var length = keys.length;
845           var index = 0;
846           var key;
847           while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);
848           return O;
849         };
850
851         var html = getBuiltIn('document', 'documentElement');
852
853         var GT = '>';
854         var LT = '<';
855         var PROTOTYPE$2 = 'prototype';
856         var SCRIPT = 'script';
857         var IE_PROTO$1 = sharedKey('IE_PROTO');
858
859         var EmptyConstructor = function () { /* empty */ };
860
861         var scriptTag = function (content) {
862           return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
863         };
864
865         // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
866         var NullProtoObjectViaActiveX = function (activeXDocument) {
867           activeXDocument.write(scriptTag(''));
868           activeXDocument.close();
869           var temp = activeXDocument.parentWindow.Object;
870           activeXDocument = null; // avoid memory leak
871           return temp;
872         };
873
874         // Create object with fake `null` prototype: use iframe Object with cleared prototype
875         var NullProtoObjectViaIFrame = function () {
876           // Thrash, waste and sodomy: IE GC bug
877           var iframe = documentCreateElement('iframe');
878           var JS = 'java' + SCRIPT + ':';
879           var iframeDocument;
880           iframe.style.display = 'none';
881           html.appendChild(iframe);
882           // https://github.com/zloirock/core-js/issues/475
883           iframe.src = String(JS);
884           iframeDocument = iframe.contentWindow.document;
885           iframeDocument.open();
886           iframeDocument.write(scriptTag('document.F=Object'));
887           iframeDocument.close();
888           return iframeDocument.F;
889         };
890
891         // Check for document.domain and active x support
892         // No need to use active x approach when document.domain is not set
893         // see https://github.com/es-shims/es5-shim/issues/150
894         // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
895         // avoid IE GC bug
896         var activeXDocument;
897         var NullProtoObject = function () {
898           try {
899             /* global ActiveXObject -- old IE */
900             activeXDocument = document.domain && new ActiveXObject('htmlfile');
901           } catch (error) { /* ignore */ }
902           NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame();
903           var length = enumBugKeys.length;
904           while (length--) delete NullProtoObject[PROTOTYPE$2][enumBugKeys[length]];
905           return NullProtoObject();
906         };
907
908         hiddenKeys$1[IE_PROTO$1] = true;
909
910         // `Object.create` method
911         // https://tc39.es/ecma262/#sec-object.create
912         var objectCreate = Object.create || function create(O, Properties) {
913           var result;
914           if (O !== null) {
915             EmptyConstructor[PROTOTYPE$2] = anObject(O);
916             result = new EmptyConstructor();
917             EmptyConstructor[PROTOTYPE$2] = null;
918             // add "__proto__" for Object.getPrototypeOf polyfill
919             result[IE_PROTO$1] = O;
920           } else result = NullProtoObject();
921           return Properties === undefined ? result : objectDefineProperties(result, Properties);
922         };
923
924         var UNSCOPABLES = wellKnownSymbol('unscopables');
925         var ArrayPrototype$1 = Array.prototype;
926
927         // Array.prototype[@@unscopables]
928         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
929         if (ArrayPrototype$1[UNSCOPABLES] == undefined) {
930           objectDefineProperty.f(ArrayPrototype$1, UNSCOPABLES, {
931             configurable: true,
932             value: objectCreate(null)
933           });
934         }
935
936         // add a key to Array.prototype[@@unscopables]
937         var addToUnscopables = function (key) {
938           ArrayPrototype$1[UNSCOPABLES][key] = true;
939         };
940
941         var iterators = {};
942
943         var correctPrototypeGetter = !fails(function () {
944           function F() { /* empty */ }
945           F.prototype.constructor = null;
946           // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
947           return Object.getPrototypeOf(new F()) !== F.prototype;
948         });
949
950         var IE_PROTO = sharedKey('IE_PROTO');
951         var ObjectPrototype$3 = Object.prototype;
952
953         // `Object.getPrototypeOf` method
954         // https://tc39.es/ecma262/#sec-object.getprototypeof
955         // eslint-disable-next-line es/no-object-getprototypeof -- safe
956         var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
957           O = toObject(O);
958           if (has$1(O, IE_PROTO)) return O[IE_PROTO];
959           if (typeof O.constructor == 'function' && O instanceof O.constructor) {
960             return O.constructor.prototype;
961           } return O instanceof Object ? ObjectPrototype$3 : null;
962         };
963
964         var ITERATOR$8 = wellKnownSymbol('iterator');
965         var BUGGY_SAFARI_ITERATORS$1 = false;
966
967         var returnThis$2 = function () { return this; };
968
969         // `%IteratorPrototype%` object
970         // https://tc39.es/ecma262/#sec-%iteratorprototype%-object
971         var IteratorPrototype$2, PrototypeOfArrayIteratorPrototype, arrayIterator;
972
973         /* eslint-disable es/no-array-prototype-keys -- safe */
974         if ([].keys) {
975           arrayIterator = [].keys();
976           // Safari 8 has buggy iterators w/o `next`
977           if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS$1 = true;
978           else {
979             PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
980             if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype$2 = PrototypeOfArrayIteratorPrototype;
981           }
982         }
983
984         var NEW_ITERATOR_PROTOTYPE = IteratorPrototype$2 == undefined || fails(function () {
985           var test = {};
986           // FF44- legacy iterators case
987           return IteratorPrototype$2[ITERATOR$8].call(test) !== test;
988         });
989
990         if (NEW_ITERATOR_PROTOTYPE) IteratorPrototype$2 = {};
991
992         // `%IteratorPrototype%[@@iterator]()` method
993         // https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator
994         if (!has$1(IteratorPrototype$2, ITERATOR$8)) {
995           createNonEnumerableProperty(IteratorPrototype$2, ITERATOR$8, returnThis$2);
996         }
997
998         var iteratorsCore = {
999           IteratorPrototype: IteratorPrototype$2,
1000           BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS$1
1001         };
1002
1003         var defineProperty$8 = objectDefineProperty.f;
1004
1005
1006
1007         var TO_STRING_TAG$4 = wellKnownSymbol('toStringTag');
1008
1009         var setToStringTag = function (it, TAG, STATIC) {
1010           if (it && !has$1(it = STATIC ? it : it.prototype, TO_STRING_TAG$4)) {
1011             defineProperty$8(it, TO_STRING_TAG$4, { configurable: true, value: TAG });
1012           }
1013         };
1014
1015         var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;
1016
1017
1018
1019
1020
1021         var returnThis$1 = function () { return this; };
1022
1023         var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
1024           var TO_STRING_TAG = NAME + ' Iterator';
1025           IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, { next: createPropertyDescriptor(1, next) });
1026           setToStringTag(IteratorConstructor, TO_STRING_TAG, false);
1027           iterators[TO_STRING_TAG] = returnThis$1;
1028           return IteratorConstructor;
1029         };
1030
1031         var aPossiblePrototype = function (it) {
1032           if (!isObject$4(it) && it !== null) {
1033             throw TypeError("Can't set " + String(it) + ' as a prototype');
1034           } return it;
1035         };
1036
1037         /* eslint-disable no-proto -- safe */
1038
1039         // `Object.setPrototypeOf` method
1040         // https://tc39.es/ecma262/#sec-object.setprototypeof
1041         // Works with __proto__ only. Old v8 can't work with null proto objects.
1042         // eslint-disable-next-line es/no-object-setprototypeof -- safe
1043         var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
1044           var CORRECT_SETTER = false;
1045           var test = {};
1046           var setter;
1047           try {
1048             // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
1049             setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
1050             setter.call(test, []);
1051             CORRECT_SETTER = test instanceof Array;
1052           } catch (error) { /* empty */ }
1053           return function setPrototypeOf(O, proto) {
1054             anObject(O);
1055             aPossiblePrototype(proto);
1056             if (CORRECT_SETTER) setter.call(O, proto);
1057             else O.__proto__ = proto;
1058             return O;
1059           };
1060         }() : undefined);
1061
1062         var IteratorPrototype = iteratorsCore.IteratorPrototype;
1063         var BUGGY_SAFARI_ITERATORS = iteratorsCore.BUGGY_SAFARI_ITERATORS;
1064         var ITERATOR$7 = wellKnownSymbol('iterator');
1065         var KEYS = 'keys';
1066         var VALUES = 'values';
1067         var ENTRIES = 'entries';
1068
1069         var returnThis = function () { return this; };
1070
1071         var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
1072           createIteratorConstructor(IteratorConstructor, NAME, next);
1073
1074           var getIterationMethod = function (KIND) {
1075             if (KIND === DEFAULT && defaultIterator) return defaultIterator;
1076             if (!BUGGY_SAFARI_ITERATORS && KIND in IterablePrototype) return IterablePrototype[KIND];
1077             switch (KIND) {
1078               case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };
1079               case VALUES: return function values() { return new IteratorConstructor(this, KIND); };
1080               case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };
1081             } return function () { return new IteratorConstructor(this); };
1082           };
1083
1084           var TO_STRING_TAG = NAME + ' Iterator';
1085           var INCORRECT_VALUES_NAME = false;
1086           var IterablePrototype = Iterable.prototype;
1087           var nativeIterator = IterablePrototype[ITERATOR$7]
1088             || IterablePrototype['@@iterator']
1089             || DEFAULT && IterablePrototype[DEFAULT];
1090           var defaultIterator = !BUGGY_SAFARI_ITERATORS && nativeIterator || getIterationMethod(DEFAULT);
1091           var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
1092           var CurrentIteratorPrototype, methods, KEY;
1093
1094           // fix native
1095           if (anyNativeIterator) {
1096             CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));
1097             if (IteratorPrototype !== Object.prototype && CurrentIteratorPrototype.next) {
1098               if (objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype) {
1099                 if (objectSetPrototypeOf) {
1100                   objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype);
1101                 } else if (typeof CurrentIteratorPrototype[ITERATOR$7] != 'function') {
1102                   createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$7, returnThis);
1103                 }
1104               }
1105               // Set @@toStringTag to native iterators
1106               setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);
1107             }
1108           }
1109
1110           // fix Array.prototype.{ values, @@iterator }.name in V8 / FF
1111           if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
1112             INCORRECT_VALUES_NAME = true;
1113             defaultIterator = function values() { return nativeIterator.call(this); };
1114           }
1115
1116           // define iterator
1117           if (IterablePrototype[ITERATOR$7] !== defaultIterator) {
1118             createNonEnumerableProperty(IterablePrototype, ITERATOR$7, defaultIterator);
1119           }
1120           iterators[NAME] = defaultIterator;
1121
1122           // export additional methods
1123           if (DEFAULT) {
1124             methods = {
1125               values: getIterationMethod(VALUES),
1126               keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
1127               entries: getIterationMethod(ENTRIES)
1128             };
1129             if (FORCED) for (KEY in methods) {
1130               if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
1131                 redefine(IterablePrototype, KEY, methods[KEY]);
1132               }
1133             } else _export({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME }, methods);
1134           }
1135
1136           return methods;
1137         };
1138
1139         var ARRAY_ITERATOR = 'Array Iterator';
1140         var setInternalState$7 = internalState.set;
1141         var getInternalState$5 = internalState.getterFor(ARRAY_ITERATOR);
1142
1143         // `Array.prototype.entries` method
1144         // https://tc39.es/ecma262/#sec-array.prototype.entries
1145         // `Array.prototype.keys` method
1146         // https://tc39.es/ecma262/#sec-array.prototype.keys
1147         // `Array.prototype.values` method
1148         // https://tc39.es/ecma262/#sec-array.prototype.values
1149         // `Array.prototype[@@iterator]` method
1150         // https://tc39.es/ecma262/#sec-array.prototype-@@iterator
1151         // `CreateArrayIterator` internal method
1152         // https://tc39.es/ecma262/#sec-createarrayiterator
1153         var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
1154           setInternalState$7(this, {
1155             type: ARRAY_ITERATOR,
1156             target: toIndexedObject(iterated), // target
1157             index: 0,                          // next index
1158             kind: kind                         // kind
1159           });
1160         // `%ArrayIteratorPrototype%.next` method
1161         // https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
1162         }, function () {
1163           var state = getInternalState$5(this);
1164           var target = state.target;
1165           var kind = state.kind;
1166           var index = state.index++;
1167           if (!target || index >= target.length) {
1168             state.target = undefined;
1169             return { value: undefined, done: true };
1170           }
1171           if (kind == 'keys') return { value: index, done: false };
1172           if (kind == 'values') return { value: target[index], done: false };
1173           return { value: [index, target[index]], done: false };
1174         }, 'values');
1175
1176         // argumentsList[@@iterator] is %ArrayProto_values%
1177         // https://tc39.es/ecma262/#sec-createunmappedargumentsobject
1178         // https://tc39.es/ecma262/#sec-createmappedargumentsobject
1179         iterators.Arguments = iterators.Array;
1180
1181         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
1182         addToUnscopables('keys');
1183         addToUnscopables('values');
1184         addToUnscopables('entries');
1185
1186         var TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');
1187         var test$2 = {};
1188
1189         test$2[TO_STRING_TAG$3] = 'z';
1190
1191         var toStringTagSupport = String(test$2) === '[object z]';
1192
1193         var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag');
1194         // ES3 wrong here
1195         var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';
1196
1197         // fallback for IE11 Script Access Denied error
1198         var tryGet = function (it, key) {
1199           try {
1200             return it[key];
1201           } catch (error) { /* empty */ }
1202         };
1203
1204         // getting tag from ES6+ `Object.prototype.toString`
1205         var classof = toStringTagSupport ? classofRaw : function (it) {
1206           var O, tag, result;
1207           return it === undefined ? 'Undefined' : it === null ? 'Null'
1208             // @@toStringTag case
1209             : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag
1210             // builtinTag case
1211             : CORRECT_ARGUMENTS ? classofRaw(O)
1212             // ES3 arguments fallback
1213             : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
1214         };
1215
1216         // `Object.prototype.toString` method implementation
1217         // https://tc39.es/ecma262/#sec-object.prototype.tostring
1218         var objectToString$1 = toStringTagSupport ? {}.toString : function toString() {
1219           return '[object ' + classof(this) + ']';
1220         };
1221
1222         // `Object.prototype.toString` method
1223         // https://tc39.es/ecma262/#sec-object.prototype.tostring
1224         if (!toStringTagSupport) {
1225           redefine(Object.prototype, 'toString', objectToString$1, { unsafe: true });
1226         }
1227
1228         // `String.prototype.{ codePointAt, at }` methods implementation
1229         var createMethod$5 = function (CONVERT_TO_STRING) {
1230           return function ($this, pos) {
1231             var S = String(requireObjectCoercible($this));
1232             var position = toInteger(pos);
1233             var size = S.length;
1234             var first, second;
1235             if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
1236             first = S.charCodeAt(position);
1237             return first < 0xD800 || first > 0xDBFF || position + 1 === size
1238               || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
1239                 ? CONVERT_TO_STRING ? S.charAt(position) : first
1240                 : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
1241           };
1242         };
1243
1244         var stringMultibyte = {
1245           // `String.prototype.codePointAt` method
1246           // https://tc39.es/ecma262/#sec-string.prototype.codepointat
1247           codeAt: createMethod$5(false),
1248           // `String.prototype.at` method
1249           // https://github.com/mathiasbynens/String.prototype.at
1250           charAt: createMethod$5(true)
1251         };
1252
1253         var charAt$1 = stringMultibyte.charAt;
1254
1255
1256
1257         var STRING_ITERATOR = 'String Iterator';
1258         var setInternalState$6 = internalState.set;
1259         var getInternalState$4 = internalState.getterFor(STRING_ITERATOR);
1260
1261         // `String.prototype[@@iterator]` method
1262         // https://tc39.es/ecma262/#sec-string.prototype-@@iterator
1263         defineIterator(String, 'String', function (iterated) {
1264           setInternalState$6(this, {
1265             type: STRING_ITERATOR,
1266             string: String(iterated),
1267             index: 0
1268           });
1269         // `%StringIteratorPrototype%.next` method
1270         // https://tc39.es/ecma262/#sec-%stringiteratorprototype%.next
1271         }, function next() {
1272           var state = getInternalState$4(this);
1273           var string = state.string;
1274           var index = state.index;
1275           var point;
1276           if (index >= string.length) return { value: undefined, done: true };
1277           point = charAt$1(string, index);
1278           state.index += point.length;
1279           return { value: point, done: false };
1280         });
1281
1282         // iterable DOM collections
1283         // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
1284         var domIterables = {
1285           CSSRuleList: 0,
1286           CSSStyleDeclaration: 0,
1287           CSSValueList: 0,
1288           ClientRectList: 0,
1289           DOMRectList: 0,
1290           DOMStringList: 0,
1291           DOMTokenList: 1,
1292           DataTransferItemList: 0,
1293           FileList: 0,
1294           HTMLAllCollection: 0,
1295           HTMLCollection: 0,
1296           HTMLFormElement: 0,
1297           HTMLSelectElement: 0,
1298           MediaList: 0,
1299           MimeTypeArray: 0,
1300           NamedNodeMap: 0,
1301           NodeList: 1,
1302           PaintRequestList: 0,
1303           Plugin: 0,
1304           PluginArray: 0,
1305           SVGLengthList: 0,
1306           SVGNumberList: 0,
1307           SVGPathSegList: 0,
1308           SVGPointList: 0,
1309           SVGStringList: 0,
1310           SVGTransformList: 0,
1311           SourceBufferList: 0,
1312           StyleSheetList: 0,
1313           TextTrackCueList: 0,
1314           TextTrackList: 0,
1315           TouchList: 0
1316         };
1317
1318         var ITERATOR$6 = wellKnownSymbol('iterator');
1319         var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
1320         var ArrayValues = es_array_iterator.values;
1321
1322         for (var COLLECTION_NAME$1 in domIterables) {
1323           var Collection$1 = global$2[COLLECTION_NAME$1];
1324           var CollectionPrototype$1 = Collection$1 && Collection$1.prototype;
1325           if (CollectionPrototype$1) {
1326             // some Chrome versions have non-configurable methods on DOMTokenList
1327             if (CollectionPrototype$1[ITERATOR$6] !== ArrayValues) try {
1328               createNonEnumerableProperty(CollectionPrototype$1, ITERATOR$6, ArrayValues);
1329             } catch (error) {
1330               CollectionPrototype$1[ITERATOR$6] = ArrayValues;
1331             }
1332             if (!CollectionPrototype$1[TO_STRING_TAG$1]) {
1333               createNonEnumerableProperty(CollectionPrototype$1, TO_STRING_TAG$1, COLLECTION_NAME$1);
1334             }
1335             if (domIterables[COLLECTION_NAME$1]) for (var METHOD_NAME in es_array_iterator) {
1336               // some Chrome versions have non-configurable methods on DOMTokenList
1337               if (CollectionPrototype$1[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {
1338                 createNonEnumerableProperty(CollectionPrototype$1, METHOD_NAME, es_array_iterator[METHOD_NAME]);
1339               } catch (error) {
1340                 CollectionPrototype$1[METHOD_NAME] = es_array_iterator[METHOD_NAME];
1341               }
1342             }
1343           }
1344         }
1345
1346         // `IsArray` abstract operation
1347         // https://tc39.es/ecma262/#sec-isarray
1348         // eslint-disable-next-line es/no-array-isarray -- safe
1349         var isArray = Array.isArray || function isArray(arg) {
1350           return classofRaw(arg) == 'Array';
1351         };
1352
1353         /* eslint-disable es/no-object-getownpropertynames -- safe */
1354
1355         var $getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
1356
1357         var toString = {}.toString;
1358
1359         var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames
1360           ? Object.getOwnPropertyNames(window) : [];
1361
1362         var getWindowNames = function (it) {
1363           try {
1364             return $getOwnPropertyNames$1(it);
1365           } catch (error) {
1366             return windowNames.slice();
1367           }
1368         };
1369
1370         // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
1371         var f$1 = function getOwnPropertyNames(it) {
1372           return windowNames && toString.call(it) == '[object Window]'
1373             ? getWindowNames(it)
1374             : $getOwnPropertyNames$1(toIndexedObject(it));
1375         };
1376
1377         var objectGetOwnPropertyNamesExternal = {
1378                 f: f$1
1379         };
1380
1381         var aFunction = function (it) {
1382           if (typeof it != 'function') {
1383             throw TypeError(String(it) + ' is not a function');
1384           } return it;
1385         };
1386
1387         // optional / simple context binding
1388         var functionBindContext = function (fn, that, length) {
1389           aFunction(fn);
1390           if (that === undefined) return fn;
1391           switch (length) {
1392             case 0: return function () {
1393               return fn.call(that);
1394             };
1395             case 1: return function (a) {
1396               return fn.call(that, a);
1397             };
1398             case 2: return function (a, b) {
1399               return fn.call(that, a, b);
1400             };
1401             case 3: return function (a, b, c) {
1402               return fn.call(that, a, b, c);
1403             };
1404           }
1405           return function (/* ...args */) {
1406             return fn.apply(that, arguments);
1407           };
1408         };
1409
1410         var SPECIES$6 = wellKnownSymbol('species');
1411
1412         // `ArraySpeciesCreate` abstract operation
1413         // https://tc39.es/ecma262/#sec-arrayspeciescreate
1414         var arraySpeciesCreate = function (originalArray, length) {
1415           var C;
1416           if (isArray(originalArray)) {
1417             C = originalArray.constructor;
1418             // cross-realm fallback
1419             if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;
1420             else if (isObject$4(C)) {
1421               C = C[SPECIES$6];
1422               if (C === null) C = undefined;
1423             }
1424           } return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
1425         };
1426
1427         var push = [].push;
1428
1429         // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterOut }` methods implementation
1430         var createMethod$4 = function (TYPE) {
1431           var IS_MAP = TYPE == 1;
1432           var IS_FILTER = TYPE == 2;
1433           var IS_SOME = TYPE == 3;
1434           var IS_EVERY = TYPE == 4;
1435           var IS_FIND_INDEX = TYPE == 6;
1436           var IS_FILTER_OUT = TYPE == 7;
1437           var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
1438           return function ($this, callbackfn, that, specificCreate) {
1439             var O = toObject($this);
1440             var self = indexedObject(O);
1441             var boundFunction = functionBindContext(callbackfn, that, 3);
1442             var length = toLength(self.length);
1443             var index = 0;
1444             var create = specificCreate || arraySpeciesCreate;
1445             var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_OUT ? create($this, 0) : undefined;
1446             var value, result;
1447             for (;length > index; index++) if (NO_HOLES || index in self) {
1448               value = self[index];
1449               result = boundFunction(value, index, O);
1450               if (TYPE) {
1451                 if (IS_MAP) target[index] = result; // map
1452                 else if (result) switch (TYPE) {
1453                   case 3: return true;              // some
1454                   case 5: return value;             // find
1455                   case 6: return index;             // findIndex
1456                   case 2: push.call(target, value); // filter
1457                 } else switch (TYPE) {
1458                   case 4: return false;             // every
1459                   case 7: push.call(target, value); // filterOut
1460                 }
1461               }
1462             }
1463             return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
1464           };
1465         };
1466
1467         var arrayIteration = {
1468           // `Array.prototype.forEach` method
1469           // https://tc39.es/ecma262/#sec-array.prototype.foreach
1470           forEach: createMethod$4(0),
1471           // `Array.prototype.map` method
1472           // https://tc39.es/ecma262/#sec-array.prototype.map
1473           map: createMethod$4(1),
1474           // `Array.prototype.filter` method
1475           // https://tc39.es/ecma262/#sec-array.prototype.filter
1476           filter: createMethod$4(2),
1477           // `Array.prototype.some` method
1478           // https://tc39.es/ecma262/#sec-array.prototype.some
1479           some: createMethod$4(3),
1480           // `Array.prototype.every` method
1481           // https://tc39.es/ecma262/#sec-array.prototype.every
1482           every: createMethod$4(4),
1483           // `Array.prototype.find` method
1484           // https://tc39.es/ecma262/#sec-array.prototype.find
1485           find: createMethod$4(5),
1486           // `Array.prototype.findIndex` method
1487           // https://tc39.es/ecma262/#sec-array.prototype.findIndex
1488           findIndex: createMethod$4(6),
1489           // `Array.prototype.filterOut` method
1490           // https://github.com/tc39/proposal-array-filtering
1491           filterOut: createMethod$4(7)
1492         };
1493
1494         var $forEach$2 = arrayIteration.forEach;
1495
1496         var HIDDEN = sharedKey('hidden');
1497         var SYMBOL = 'Symbol';
1498         var PROTOTYPE$1 = 'prototype';
1499         var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');
1500         var setInternalState$5 = internalState.set;
1501         var getInternalState$3 = internalState.getterFor(SYMBOL);
1502         var ObjectPrototype$2 = Object[PROTOTYPE$1];
1503         var $Symbol = global$2.Symbol;
1504         var $stringify = getBuiltIn('JSON', 'stringify');
1505         var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
1506         var nativeDefineProperty = objectDefineProperty.f;
1507         var nativeGetOwnPropertyNames = objectGetOwnPropertyNamesExternal.f;
1508         var nativePropertyIsEnumerable = objectPropertyIsEnumerable.f;
1509         var AllSymbols = shared('symbols');
1510         var ObjectPrototypeSymbols = shared('op-symbols');
1511         var StringToSymbolRegistry = shared('string-to-symbol-registry');
1512         var SymbolToStringRegistry = shared('symbol-to-string-registry');
1513         var WellKnownSymbolsStore = shared('wks');
1514         var QObject = global$2.QObject;
1515         // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
1516         var USE_SETTER = !QObject || !QObject[PROTOTYPE$1] || !QObject[PROTOTYPE$1].findChild;
1517
1518         // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
1519         var setSymbolDescriptor = descriptors && fails(function () {
1520           return objectCreate(nativeDefineProperty({}, 'a', {
1521             get: function () { return nativeDefineProperty(this, 'a', { value: 7 }).a; }
1522           })).a != 7;
1523         }) ? function (O, P, Attributes) {
1524           var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype$2, P);
1525           if (ObjectPrototypeDescriptor) delete ObjectPrototype$2[P];
1526           nativeDefineProperty(O, P, Attributes);
1527           if (ObjectPrototypeDescriptor && O !== ObjectPrototype$2) {
1528             nativeDefineProperty(ObjectPrototype$2, P, ObjectPrototypeDescriptor);
1529           }
1530         } : nativeDefineProperty;
1531
1532         var wrap$2 = function (tag, description) {
1533           var symbol = AllSymbols[tag] = objectCreate($Symbol[PROTOTYPE$1]);
1534           setInternalState$5(symbol, {
1535             type: SYMBOL,
1536             tag: tag,
1537             description: description
1538           });
1539           if (!descriptors) symbol.description = description;
1540           return symbol;
1541         };
1542
1543         var isSymbol$1 = useSymbolAsUid ? function (it) {
1544           return typeof it == 'symbol';
1545         } : function (it) {
1546           return Object(it) instanceof $Symbol;
1547         };
1548
1549         var $defineProperty = function defineProperty(O, P, Attributes) {
1550           if (O === ObjectPrototype$2) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
1551           anObject(O);
1552           var key = toPrimitive(P, true);
1553           anObject(Attributes);
1554           if (has$1(AllSymbols, key)) {
1555             if (!Attributes.enumerable) {
1556               if (!has$1(O, HIDDEN)) nativeDefineProperty(O, HIDDEN, createPropertyDescriptor(1, {}));
1557               O[HIDDEN][key] = true;
1558             } else {
1559               if (has$1(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
1560               Attributes = objectCreate(Attributes, { enumerable: createPropertyDescriptor(0, false) });
1561             } return setSymbolDescriptor(O, key, Attributes);
1562           } return nativeDefineProperty(O, key, Attributes);
1563         };
1564
1565         var $defineProperties = function defineProperties(O, Properties) {
1566           anObject(O);
1567           var properties = toIndexedObject(Properties);
1568           var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties));
1569           $forEach$2(keys, function (key) {
1570             if (!descriptors || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
1571           });
1572           return O;
1573         };
1574
1575         var $create = function create(O, Properties) {
1576           return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties);
1577         };
1578
1579         var $propertyIsEnumerable = function propertyIsEnumerable(V) {
1580           var P = toPrimitive(V, true);
1581           var enumerable = nativePropertyIsEnumerable.call(this, P);
1582           if (this === ObjectPrototype$2 && has$1(AllSymbols, P) && !has$1(ObjectPrototypeSymbols, P)) return false;
1583           return enumerable || !has$1(this, P) || !has$1(AllSymbols, P) || has$1(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
1584         };
1585
1586         var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
1587           var it = toIndexedObject(O);
1588           var key = toPrimitive(P, true);
1589           if (it === ObjectPrototype$2 && has$1(AllSymbols, key) && !has$1(ObjectPrototypeSymbols, key)) return;
1590           var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);
1591           if (descriptor && has$1(AllSymbols, key) && !(has$1(it, HIDDEN) && it[HIDDEN][key])) {
1592             descriptor.enumerable = true;
1593           }
1594           return descriptor;
1595         };
1596
1597         var $getOwnPropertyNames = function getOwnPropertyNames(O) {
1598           var names = nativeGetOwnPropertyNames(toIndexedObject(O));
1599           var result = [];
1600           $forEach$2(names, function (key) {
1601             if (!has$1(AllSymbols, key) && !has$1(hiddenKeys$1, key)) result.push(key);
1602           });
1603           return result;
1604         };
1605
1606         var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
1607           var IS_OBJECT_PROTOTYPE = O === ObjectPrototype$2;
1608           var names = nativeGetOwnPropertyNames(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));
1609           var result = [];
1610           $forEach$2(names, function (key) {
1611             if (has$1(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has$1(ObjectPrototype$2, key))) {
1612               result.push(AllSymbols[key]);
1613             }
1614           });
1615           return result;
1616         };
1617
1618         // `Symbol` constructor
1619         // https://tc39.es/ecma262/#sec-symbol-constructor
1620         if (!nativeSymbol) {
1621           $Symbol = function Symbol() {
1622             if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
1623             var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
1624             var tag = uid(description);
1625             var setter = function (value) {
1626               if (this === ObjectPrototype$2) setter.call(ObjectPrototypeSymbols, value);
1627               if (has$1(this, HIDDEN) && has$1(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
1628               setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
1629             };
1630             if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype$2, tag, { configurable: true, set: setter });
1631             return wrap$2(tag, description);
1632           };
1633
1634           redefine($Symbol[PROTOTYPE$1], 'toString', function toString() {
1635             return getInternalState$3(this).tag;
1636           });
1637
1638           redefine($Symbol, 'withoutSetter', function (description) {
1639             return wrap$2(uid(description), description);
1640           });
1641
1642           objectPropertyIsEnumerable.f = $propertyIsEnumerable;
1643           objectDefineProperty.f = $defineProperty;
1644           objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor;
1645           objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames;
1646           objectGetOwnPropertySymbols.f = $getOwnPropertySymbols;
1647
1648           wellKnownSymbolWrapped.f = function (name) {
1649             return wrap$2(wellKnownSymbol(name), name);
1650           };
1651
1652           if (descriptors) {
1653             // https://github.com/tc39/proposal-Symbol-description
1654             nativeDefineProperty($Symbol[PROTOTYPE$1], 'description', {
1655               configurable: true,
1656               get: function description() {
1657                 return getInternalState$3(this).description;
1658               }
1659             });
1660             {
1661               redefine(ObjectPrototype$2, 'propertyIsEnumerable', $propertyIsEnumerable, { unsafe: true });
1662             }
1663           }
1664         }
1665
1666         _export({ global: true, wrap: true, forced: !nativeSymbol, sham: !nativeSymbol }, {
1667           Symbol: $Symbol
1668         });
1669
1670         $forEach$2(objectKeys(WellKnownSymbolsStore), function (name) {
1671           defineWellKnownSymbol(name);
1672         });
1673
1674         _export({ target: SYMBOL, stat: true, forced: !nativeSymbol }, {
1675           // `Symbol.for` method
1676           // https://tc39.es/ecma262/#sec-symbol.for
1677           'for': function (key) {
1678             var string = String(key);
1679             if (has$1(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
1680             var symbol = $Symbol(string);
1681             StringToSymbolRegistry[string] = symbol;
1682             SymbolToStringRegistry[symbol] = string;
1683             return symbol;
1684           },
1685           // `Symbol.keyFor` method
1686           // https://tc39.es/ecma262/#sec-symbol.keyfor
1687           keyFor: function keyFor(sym) {
1688             if (!isSymbol$1(sym)) throw TypeError(sym + ' is not a symbol');
1689             if (has$1(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
1690           },
1691           useSetter: function () { USE_SETTER = true; },
1692           useSimple: function () { USE_SETTER = false; }
1693         });
1694
1695         _export({ target: 'Object', stat: true, forced: !nativeSymbol, sham: !descriptors }, {
1696           // `Object.create` method
1697           // https://tc39.es/ecma262/#sec-object.create
1698           create: $create,
1699           // `Object.defineProperty` method
1700           // https://tc39.es/ecma262/#sec-object.defineproperty
1701           defineProperty: $defineProperty,
1702           // `Object.defineProperties` method
1703           // https://tc39.es/ecma262/#sec-object.defineproperties
1704           defineProperties: $defineProperties,
1705           // `Object.getOwnPropertyDescriptor` method
1706           // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
1707           getOwnPropertyDescriptor: $getOwnPropertyDescriptor
1708         });
1709
1710         _export({ target: 'Object', stat: true, forced: !nativeSymbol }, {
1711           // `Object.getOwnPropertyNames` method
1712           // https://tc39.es/ecma262/#sec-object.getownpropertynames
1713           getOwnPropertyNames: $getOwnPropertyNames,
1714           // `Object.getOwnPropertySymbols` method
1715           // https://tc39.es/ecma262/#sec-object.getownpropertysymbols
1716           getOwnPropertySymbols: $getOwnPropertySymbols
1717         });
1718
1719         // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
1720         // https://bugs.chromium.org/p/v8/issues/detail?id=3443
1721         _export({ target: 'Object', stat: true, forced: fails(function () { objectGetOwnPropertySymbols.f(1); }) }, {
1722           getOwnPropertySymbols: function getOwnPropertySymbols(it) {
1723             return objectGetOwnPropertySymbols.f(toObject(it));
1724           }
1725         });
1726
1727         // `JSON.stringify` method behavior with symbols
1728         // https://tc39.es/ecma262/#sec-json.stringify
1729         if ($stringify) {
1730           var FORCED_JSON_STRINGIFY = !nativeSymbol || fails(function () {
1731             var symbol = $Symbol();
1732             // MS Edge converts symbol values to JSON as {}
1733             return $stringify([symbol]) != '[null]'
1734               // WebKit converts symbol values to JSON as null
1735               || $stringify({ a: symbol }) != '{}'
1736               // V8 throws on boxed symbols
1737               || $stringify(Object(symbol)) != '{}';
1738           });
1739
1740           _export({ target: 'JSON', stat: true, forced: FORCED_JSON_STRINGIFY }, {
1741             // eslint-disable-next-line no-unused-vars -- required for `.length`
1742             stringify: function stringify(it, replacer, space) {
1743               var args = [it];
1744               var index = 1;
1745               var $replacer;
1746               while (arguments.length > index) args.push(arguments[index++]);
1747               $replacer = replacer;
1748               if (!isObject$4(replacer) && it === undefined || isSymbol$1(it)) return; // IE8 returns string on undefined
1749               if (!isArray(replacer)) replacer = function (key, value) {
1750                 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
1751                 if (!isSymbol$1(value)) return value;
1752               };
1753               args[1] = replacer;
1754               return $stringify.apply(null, args);
1755             }
1756           });
1757         }
1758
1759         // `Symbol.prototype[@@toPrimitive]` method
1760         // https://tc39.es/ecma262/#sec-symbol.prototype-@@toprimitive
1761         if (!$Symbol[PROTOTYPE$1][TO_PRIMITIVE]) {
1762           createNonEnumerableProperty($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf);
1763         }
1764         // `Symbol.prototype[@@toStringTag]` property
1765         // https://tc39.es/ecma262/#sec-symbol.prototype-@@tostringtag
1766         setToStringTag($Symbol, SYMBOL);
1767
1768         hiddenKeys$1[HIDDEN] = true;
1769
1770         var defineProperty$7 = objectDefineProperty.f;
1771
1772
1773         var NativeSymbol = global$2.Symbol;
1774
1775         if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) ||
1776           // Safari 12 bug
1777           NativeSymbol().description !== undefined
1778         )) {
1779           var EmptyStringDescriptionStore = {};
1780           // wrap Symbol constructor for correct work with undefined description
1781           var SymbolWrapper = function Symbol() {
1782             var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
1783             var result = this instanceof SymbolWrapper
1784               ? new NativeSymbol(description)
1785               // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
1786               : description === undefined ? NativeSymbol() : NativeSymbol(description);
1787             if (description === '') EmptyStringDescriptionStore[result] = true;
1788             return result;
1789           };
1790           copyConstructorProperties(SymbolWrapper, NativeSymbol);
1791           var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
1792           symbolPrototype.constructor = SymbolWrapper;
1793
1794           var symbolToString = symbolPrototype.toString;
1795           var native = String(NativeSymbol('test')) == 'Symbol(test)';
1796           var regexp = /^Symbol\((.*)\)[^)]+$/;
1797           defineProperty$7(symbolPrototype, 'description', {
1798             configurable: true,
1799             get: function description() {
1800               var symbol = isObject$4(this) ? this.valueOf() : this;
1801               var string = symbolToString.call(symbol);
1802               if (has$1(EmptyStringDescriptionStore, symbol)) return '';
1803               var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
1804               return desc === '' ? undefined : desc;
1805             }
1806           });
1807
1808           _export({ global: true, forced: true }, {
1809             Symbol: SymbolWrapper
1810           });
1811         }
1812
1813         // eslint-disable-next-line es/no-typed-arrays -- safe
1814         var arrayBufferNative = typeof ArrayBuffer !== 'undefined' && typeof DataView !== 'undefined';
1815
1816         var redefineAll = function (target, src, options) {
1817           for (var key in src) redefine(target, key, src[key], options);
1818           return target;
1819         };
1820
1821         var anInstance = function (it, Constructor, name) {
1822           if (!(it instanceof Constructor)) {
1823             throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
1824           } return it;
1825         };
1826
1827         // `ToIndex` abstract operation
1828         // https://tc39.es/ecma262/#sec-toindex
1829         var toIndex = function (it) {
1830           if (it === undefined) return 0;
1831           var number = toInteger(it);
1832           var length = toLength(number);
1833           if (number !== length) throw RangeError('Wrong length or index');
1834           return length;
1835         };
1836
1837         // IEEE754 conversions based on https://github.com/feross/ieee754
1838         var abs$4 = Math.abs;
1839         var pow$2 = Math.pow;
1840         var floor$6 = Math.floor;
1841         var log$2 = Math.log;
1842         var LN2 = Math.LN2;
1843
1844         var pack = function (number, mantissaLength, bytes) {
1845           var buffer = new Array(bytes);
1846           var exponentLength = bytes * 8 - mantissaLength - 1;
1847           var eMax = (1 << exponentLength) - 1;
1848           var eBias = eMax >> 1;
1849           var rt = mantissaLength === 23 ? pow$2(2, -24) - pow$2(2, -77) : 0;
1850           var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
1851           var index = 0;
1852           var exponent, mantissa, c;
1853           number = abs$4(number);
1854           // eslint-disable-next-line no-self-compare -- NaN check
1855           if (number != number || number === Infinity) {
1856             // eslint-disable-next-line no-self-compare -- NaN check
1857             mantissa = number != number ? 1 : 0;
1858             exponent = eMax;
1859           } else {
1860             exponent = floor$6(log$2(number) / LN2);
1861             if (number * (c = pow$2(2, -exponent)) < 1) {
1862               exponent--;
1863               c *= 2;
1864             }
1865             if (exponent + eBias >= 1) {
1866               number += rt / c;
1867             } else {
1868               number += rt * pow$2(2, 1 - eBias);
1869             }
1870             if (number * c >= 2) {
1871               exponent++;
1872               c /= 2;
1873             }
1874             if (exponent + eBias >= eMax) {
1875               mantissa = 0;
1876               exponent = eMax;
1877             } else if (exponent + eBias >= 1) {
1878               mantissa = (number * c - 1) * pow$2(2, mantissaLength);
1879               exponent = exponent + eBias;
1880             } else {
1881               mantissa = number * pow$2(2, eBias - 1) * pow$2(2, mantissaLength);
1882               exponent = 0;
1883             }
1884           }
1885           for (; mantissaLength >= 8; buffer[index++] = mantissa & 255, mantissa /= 256, mantissaLength -= 8);
1886           exponent = exponent << mantissaLength | mantissa;
1887           exponentLength += mantissaLength;
1888           for (; exponentLength > 0; buffer[index++] = exponent & 255, exponent /= 256, exponentLength -= 8);
1889           buffer[--index] |= sign * 128;
1890           return buffer;
1891         };
1892
1893         var unpack = function (buffer, mantissaLength) {
1894           var bytes = buffer.length;
1895           var exponentLength = bytes * 8 - mantissaLength - 1;
1896           var eMax = (1 << exponentLength) - 1;
1897           var eBias = eMax >> 1;
1898           var nBits = exponentLength - 7;
1899           var index = bytes - 1;
1900           var sign = buffer[index--];
1901           var exponent = sign & 127;
1902           var mantissa;
1903           sign >>= 7;
1904           for (; nBits > 0; exponent = exponent * 256 + buffer[index], index--, nBits -= 8);
1905           mantissa = exponent & (1 << -nBits) - 1;
1906           exponent >>= -nBits;
1907           nBits += mantissaLength;
1908           for (; nBits > 0; mantissa = mantissa * 256 + buffer[index], index--, nBits -= 8);
1909           if (exponent === 0) {
1910             exponent = 1 - eBias;
1911           } else if (exponent === eMax) {
1912             return mantissa ? NaN : sign ? -Infinity : Infinity;
1913           } else {
1914             mantissa = mantissa + pow$2(2, mantissaLength);
1915             exponent = exponent - eBias;
1916           } return (sign ? -1 : 1) * mantissa * pow$2(2, exponent - mantissaLength);
1917         };
1918
1919         var ieee754$1 = {
1920           pack: pack,
1921           unpack: unpack
1922         };
1923
1924         // `Array.prototype.fill` method implementation
1925         // https://tc39.es/ecma262/#sec-array.prototype.fill
1926         var arrayFill = function fill(value /* , start = 0, end = @length */) {
1927           var O = toObject(this);
1928           var length = toLength(O.length);
1929           var argumentsLength = arguments.length;
1930           var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);
1931           var end = argumentsLength > 2 ? arguments[2] : undefined;
1932           var endPos = end === undefined ? length : toAbsoluteIndex(end, length);
1933           while (endPos > index) O[index++] = value;
1934           return O;
1935         };
1936
1937         var getOwnPropertyNames$3 = objectGetOwnPropertyNames.f;
1938         var defineProperty$6 = objectDefineProperty.f;
1939
1940
1941
1942
1943         var getInternalState$2 = internalState.get;
1944         var setInternalState$4 = internalState.set;
1945         var ARRAY_BUFFER$1 = 'ArrayBuffer';
1946         var DATA_VIEW = 'DataView';
1947         var PROTOTYPE = 'prototype';
1948         var WRONG_LENGTH = 'Wrong length';
1949         var WRONG_INDEX = 'Wrong index';
1950         var NativeArrayBuffer$1 = global$2[ARRAY_BUFFER$1];
1951         var $ArrayBuffer = NativeArrayBuffer$1;
1952         var $DataView = global$2[DATA_VIEW];
1953         var $DataViewPrototype = $DataView && $DataView[PROTOTYPE];
1954         var ObjectPrototype$1 = Object.prototype;
1955         var RangeError$1 = global$2.RangeError;
1956
1957         var packIEEE754 = ieee754$1.pack;
1958         var unpackIEEE754 = ieee754$1.unpack;
1959
1960         var packInt8 = function (number) {
1961           return [number & 0xFF];
1962         };
1963
1964         var packInt16 = function (number) {
1965           return [number & 0xFF, number >> 8 & 0xFF];
1966         };
1967
1968         var packInt32 = function (number) {
1969           return [number & 0xFF, number >> 8 & 0xFF, number >> 16 & 0xFF, number >> 24 & 0xFF];
1970         };
1971
1972         var unpackInt32 = function (buffer) {
1973           return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
1974         };
1975
1976         var packFloat32 = function (number) {
1977           return packIEEE754(number, 23, 4);
1978         };
1979
1980         var packFloat64 = function (number) {
1981           return packIEEE754(number, 52, 8);
1982         };
1983
1984         var addGetter = function (Constructor, key) {
1985           defineProperty$6(Constructor[PROTOTYPE], key, { get: function () { return getInternalState$2(this)[key]; } });
1986         };
1987
1988         var get$4 = function (view, count, index, isLittleEndian) {
1989           var intIndex = toIndex(index);
1990           var store = getInternalState$2(view);
1991           if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
1992           var bytes = getInternalState$2(store.buffer).bytes;
1993           var start = intIndex + store.byteOffset;
1994           var pack = bytes.slice(start, start + count);
1995           return isLittleEndian ? pack : pack.reverse();
1996         };
1997
1998         var set$3 = function (view, count, index, conversion, value, isLittleEndian) {
1999           var intIndex = toIndex(index);
2000           var store = getInternalState$2(view);
2001           if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
2002           var bytes = getInternalState$2(store.buffer).bytes;
2003           var start = intIndex + store.byteOffset;
2004           var pack = conversion(+value);
2005           for (var i = 0; i < count; i++) bytes[start + i] = pack[isLittleEndian ? i : count - i - 1];
2006         };
2007
2008         if (!arrayBufferNative) {
2009           $ArrayBuffer = function ArrayBuffer(length) {
2010             anInstance(this, $ArrayBuffer, ARRAY_BUFFER$1);
2011             var byteLength = toIndex(length);
2012             setInternalState$4(this, {
2013               bytes: arrayFill.call(new Array(byteLength), 0),
2014               byteLength: byteLength
2015             });
2016             if (!descriptors) this.byteLength = byteLength;
2017           };
2018
2019           $DataView = function DataView(buffer, byteOffset, byteLength) {
2020             anInstance(this, $DataView, DATA_VIEW);
2021             anInstance(buffer, $ArrayBuffer, DATA_VIEW);
2022             var bufferLength = getInternalState$2(buffer).byteLength;
2023             var offset = toInteger(byteOffset);
2024             if (offset < 0 || offset > bufferLength) throw RangeError$1('Wrong offset');
2025             byteLength = byteLength === undefined ? bufferLength - offset : toLength(byteLength);
2026             if (offset + byteLength > bufferLength) throw RangeError$1(WRONG_LENGTH);
2027             setInternalState$4(this, {
2028               buffer: buffer,
2029               byteLength: byteLength,
2030               byteOffset: offset
2031             });
2032             if (!descriptors) {
2033               this.buffer = buffer;
2034               this.byteLength = byteLength;
2035               this.byteOffset = offset;
2036             }
2037           };
2038
2039           if (descriptors) {
2040             addGetter($ArrayBuffer, 'byteLength');
2041             addGetter($DataView, 'buffer');
2042             addGetter($DataView, 'byteLength');
2043             addGetter($DataView, 'byteOffset');
2044           }
2045
2046           redefineAll($DataView[PROTOTYPE], {
2047             getInt8: function getInt8(byteOffset) {
2048               return get$4(this, 1, byteOffset)[0] << 24 >> 24;
2049             },
2050             getUint8: function getUint8(byteOffset) {
2051               return get$4(this, 1, byteOffset)[0];
2052             },
2053             getInt16: function getInt16(byteOffset /* , littleEndian */) {
2054               var bytes = get$4(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
2055               return (bytes[1] << 8 | bytes[0]) << 16 >> 16;
2056             },
2057             getUint16: function getUint16(byteOffset /* , littleEndian */) {
2058               var bytes = get$4(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
2059               return bytes[1] << 8 | bytes[0];
2060             },
2061             getInt32: function getInt32(byteOffset /* , littleEndian */) {
2062               return unpackInt32(get$4(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined));
2063             },
2064             getUint32: function getUint32(byteOffset /* , littleEndian */) {
2065               return unpackInt32(get$4(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined)) >>> 0;
2066             },
2067             getFloat32: function getFloat32(byteOffset /* , littleEndian */) {
2068               return unpackIEEE754(get$4(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 23);
2069             },
2070             getFloat64: function getFloat64(byteOffset /* , littleEndian */) {
2071               return unpackIEEE754(get$4(this, 8, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 52);
2072             },
2073             setInt8: function setInt8(byteOffset, value) {
2074               set$3(this, 1, byteOffset, packInt8, value);
2075             },
2076             setUint8: function setUint8(byteOffset, value) {
2077               set$3(this, 1, byteOffset, packInt8, value);
2078             },
2079             setInt16: function setInt16(byteOffset, value /* , littleEndian */) {
2080               set$3(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
2081             },
2082             setUint16: function setUint16(byteOffset, value /* , littleEndian */) {
2083               set$3(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
2084             },
2085             setInt32: function setInt32(byteOffset, value /* , littleEndian */) {
2086               set$3(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
2087             },
2088             setUint32: function setUint32(byteOffset, value /* , littleEndian */) {
2089               set$3(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
2090             },
2091             setFloat32: function setFloat32(byteOffset, value /* , littleEndian */) {
2092               set$3(this, 4, byteOffset, packFloat32, value, arguments.length > 2 ? arguments[2] : undefined);
2093             },
2094             setFloat64: function setFloat64(byteOffset, value /* , littleEndian */) {
2095               set$3(this, 8, byteOffset, packFloat64, value, arguments.length > 2 ? arguments[2] : undefined);
2096             }
2097           });
2098         } else {
2099           /* eslint-disable no-new -- required for testing */
2100           if (!fails(function () {
2101             NativeArrayBuffer$1(1);
2102           }) || !fails(function () {
2103             new NativeArrayBuffer$1(-1);
2104           }) || fails(function () {
2105             new NativeArrayBuffer$1();
2106             new NativeArrayBuffer$1(1.5);
2107             new NativeArrayBuffer$1(NaN);
2108             return NativeArrayBuffer$1.name != ARRAY_BUFFER$1;
2109           })) {
2110           /* eslint-enable no-new -- required for testing */
2111             $ArrayBuffer = function ArrayBuffer(length) {
2112               anInstance(this, $ArrayBuffer);
2113               return new NativeArrayBuffer$1(toIndex(length));
2114             };
2115             var ArrayBufferPrototype = $ArrayBuffer[PROTOTYPE] = NativeArrayBuffer$1[PROTOTYPE];
2116             for (var keys$2 = getOwnPropertyNames$3(NativeArrayBuffer$1), j$2 = 0, key$1; keys$2.length > j$2;) {
2117               if (!((key$1 = keys$2[j$2++]) in $ArrayBuffer)) {
2118                 createNonEnumerableProperty($ArrayBuffer, key$1, NativeArrayBuffer$1[key$1]);
2119               }
2120             }
2121             ArrayBufferPrototype.constructor = $ArrayBuffer;
2122           }
2123
2124           // WebKit bug - the same parent prototype for typed arrays and data view
2125           if (objectSetPrototypeOf && objectGetPrototypeOf($DataViewPrototype) !== ObjectPrototype$1) {
2126             objectSetPrototypeOf($DataViewPrototype, ObjectPrototype$1);
2127           }
2128
2129           // iOS Safari 7.x bug
2130           var testView = new $DataView(new $ArrayBuffer(2));
2131           var $setInt8 = $DataViewPrototype.setInt8;
2132           testView.setInt8(0, 2147483648);
2133           testView.setInt8(1, 2147483649);
2134           if (testView.getInt8(0) || !testView.getInt8(1)) redefineAll($DataViewPrototype, {
2135             setInt8: function setInt8(byteOffset, value) {
2136               $setInt8.call(this, byteOffset, value << 24 >> 24);
2137             },
2138             setUint8: function setUint8(byteOffset, value) {
2139               $setInt8.call(this, byteOffset, value << 24 >> 24);
2140             }
2141           }, { unsafe: true });
2142         }
2143
2144         setToStringTag($ArrayBuffer, ARRAY_BUFFER$1);
2145         setToStringTag($DataView, DATA_VIEW);
2146
2147         var arrayBuffer = {
2148           ArrayBuffer: $ArrayBuffer,
2149           DataView: $DataView
2150         };
2151
2152         var SPECIES$5 = wellKnownSymbol('species');
2153
2154         // `SpeciesConstructor` abstract operation
2155         // https://tc39.es/ecma262/#sec-speciesconstructor
2156         var speciesConstructor = function (O, defaultConstructor) {
2157           var C = anObject(O).constructor;
2158           var S;
2159           return C === undefined || (S = anObject(C)[SPECIES$5]) == undefined ? defaultConstructor : aFunction(S);
2160         };
2161
2162         var ArrayBuffer$3 = arrayBuffer.ArrayBuffer;
2163         var DataView$1 = arrayBuffer.DataView;
2164         var nativeArrayBufferSlice = ArrayBuffer$3.prototype.slice;
2165
2166         var INCORRECT_SLICE = fails(function () {
2167           return !new ArrayBuffer$3(2).slice(1, undefined).byteLength;
2168         });
2169
2170         // `ArrayBuffer.prototype.slice` method
2171         // https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
2172         _export({ target: 'ArrayBuffer', proto: true, unsafe: true, forced: INCORRECT_SLICE }, {
2173           slice: function slice(start, end) {
2174             if (nativeArrayBufferSlice !== undefined && end === undefined) {
2175               return nativeArrayBufferSlice.call(anObject(this), start); // FF fix
2176             }
2177             var length = anObject(this).byteLength;
2178             var first = toAbsoluteIndex(start, length);
2179             var fin = toAbsoluteIndex(end === undefined ? length : end, length);
2180             var result = new (speciesConstructor(this, ArrayBuffer$3))(toLength(fin - first));
2181             var viewSource = new DataView$1(this);
2182             var viewTarget = new DataView$1(result);
2183             var index = 0;
2184             while (first < fin) {
2185               viewTarget.setUint8(index++, viewSource.getUint8(first++));
2186             } return result;
2187           }
2188         });
2189
2190         // `DataView` constructor
2191         // https://tc39.es/ecma262/#sec-dataview-constructor
2192         _export({ global: true, forced: !arrayBufferNative }, {
2193           DataView: arrayBuffer.DataView
2194         });
2195
2196         var defineProperty$5 = objectDefineProperty.f;
2197
2198
2199
2200
2201
2202         var Int8Array$3 = global$2.Int8Array;
2203         var Int8ArrayPrototype = Int8Array$3 && Int8Array$3.prototype;
2204         var Uint8ClampedArray = global$2.Uint8ClampedArray;
2205         var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
2206         var TypedArray = Int8Array$3 && objectGetPrototypeOf(Int8Array$3);
2207         var TypedArrayPrototype = Int8ArrayPrototype && objectGetPrototypeOf(Int8ArrayPrototype);
2208         var ObjectPrototype = Object.prototype;
2209         var isPrototypeOf = ObjectPrototype.isPrototypeOf;
2210
2211         var TO_STRING_TAG = wellKnownSymbol('toStringTag');
2212         var TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG');
2213         // Fixing native typed arrays in Opera Presto crashes the browser, see #595
2214         var NATIVE_ARRAY_BUFFER_VIEWS$2 = arrayBufferNative && !!objectSetPrototypeOf && classof(global$2.opera) !== 'Opera';
2215         var TYPED_ARRAY_TAG_REQIRED = false;
2216         var NAME$1;
2217
2218         var TypedArrayConstructorsList = {
2219           Int8Array: 1,
2220           Uint8Array: 1,
2221           Uint8ClampedArray: 1,
2222           Int16Array: 2,
2223           Uint16Array: 2,
2224           Int32Array: 4,
2225           Uint32Array: 4,
2226           Float32Array: 4,
2227           Float64Array: 8
2228         };
2229
2230         var BigIntArrayConstructorsList = {
2231           BigInt64Array: 8,
2232           BigUint64Array: 8
2233         };
2234
2235         var isView = function isView(it) {
2236           if (!isObject$4(it)) return false;
2237           var klass = classof(it);
2238           return klass === 'DataView'
2239             || has$1(TypedArrayConstructorsList, klass)
2240             || has$1(BigIntArrayConstructorsList, klass);
2241         };
2242
2243         var isTypedArray = function (it) {
2244           if (!isObject$4(it)) return false;
2245           var klass = classof(it);
2246           return has$1(TypedArrayConstructorsList, klass)
2247             || has$1(BigIntArrayConstructorsList, klass);
2248         };
2249
2250         var aTypedArray$m = function (it) {
2251           if (isTypedArray(it)) return it;
2252           throw TypeError('Target is not a typed array');
2253         };
2254
2255         var aTypedArrayConstructor$4 = function (C) {
2256           if (objectSetPrototypeOf) {
2257             if (isPrototypeOf.call(TypedArray, C)) return C;
2258           } else for (var ARRAY in TypedArrayConstructorsList) if (has$1(TypedArrayConstructorsList, NAME$1)) {
2259             var TypedArrayConstructor = global$2[ARRAY];
2260             if (TypedArrayConstructor && (C === TypedArrayConstructor || isPrototypeOf.call(TypedArrayConstructor, C))) {
2261               return C;
2262             }
2263           } throw TypeError('Target is not a typed array constructor');
2264         };
2265
2266         var exportTypedArrayMethod$n = function (KEY, property, forced) {
2267           if (!descriptors) return;
2268           if (forced) for (var ARRAY in TypedArrayConstructorsList) {
2269             var TypedArrayConstructor = global$2[ARRAY];
2270             if (TypedArrayConstructor && has$1(TypedArrayConstructor.prototype, KEY)) try {
2271               delete TypedArrayConstructor.prototype[KEY];
2272             } catch (error) { /* empty */ }
2273           }
2274           if (!TypedArrayPrototype[KEY] || forced) {
2275             redefine(TypedArrayPrototype, KEY, forced ? property
2276               : NATIVE_ARRAY_BUFFER_VIEWS$2 && Int8ArrayPrototype[KEY] || property);
2277           }
2278         };
2279
2280         var exportTypedArrayStaticMethod$1 = function (KEY, property, forced) {
2281           var ARRAY, TypedArrayConstructor;
2282           if (!descriptors) return;
2283           if (objectSetPrototypeOf) {
2284             if (forced) for (ARRAY in TypedArrayConstructorsList) {
2285               TypedArrayConstructor = global$2[ARRAY];
2286               if (TypedArrayConstructor && has$1(TypedArrayConstructor, KEY)) try {
2287                 delete TypedArrayConstructor[KEY];
2288               } catch (error) { /* empty */ }
2289             }
2290             if (!TypedArray[KEY] || forced) {
2291               // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
2292               try {
2293                 return redefine(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS$2 && TypedArray[KEY] || property);
2294               } catch (error) { /* empty */ }
2295             } else return;
2296           }
2297           for (ARRAY in TypedArrayConstructorsList) {
2298             TypedArrayConstructor = global$2[ARRAY];
2299             if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
2300               redefine(TypedArrayConstructor, KEY, property);
2301             }
2302           }
2303         };
2304
2305         for (NAME$1 in TypedArrayConstructorsList) {
2306           if (!global$2[NAME$1]) NATIVE_ARRAY_BUFFER_VIEWS$2 = false;
2307         }
2308
2309         // WebKit bug - typed arrays constructors prototype is Object.prototype
2310         if (!NATIVE_ARRAY_BUFFER_VIEWS$2 || typeof TypedArray != 'function' || TypedArray === Function.prototype) {
2311           // eslint-disable-next-line no-shadow -- safe
2312           TypedArray = function TypedArray() {
2313             throw TypeError('Incorrect invocation');
2314           };
2315           if (NATIVE_ARRAY_BUFFER_VIEWS$2) for (NAME$1 in TypedArrayConstructorsList) {
2316             if (global$2[NAME$1]) objectSetPrototypeOf(global$2[NAME$1], TypedArray);
2317           }
2318         }
2319
2320         if (!NATIVE_ARRAY_BUFFER_VIEWS$2 || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype) {
2321           TypedArrayPrototype = TypedArray.prototype;
2322           if (NATIVE_ARRAY_BUFFER_VIEWS$2) for (NAME$1 in TypedArrayConstructorsList) {
2323             if (global$2[NAME$1]) objectSetPrototypeOf(global$2[NAME$1].prototype, TypedArrayPrototype);
2324           }
2325         }
2326
2327         // WebKit bug - one more object in Uint8ClampedArray prototype chain
2328         if (NATIVE_ARRAY_BUFFER_VIEWS$2 && objectGetPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) {
2329           objectSetPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype);
2330         }
2331
2332         if (descriptors && !has$1(TypedArrayPrototype, TO_STRING_TAG)) {
2333           TYPED_ARRAY_TAG_REQIRED = true;
2334           defineProperty$5(TypedArrayPrototype, TO_STRING_TAG, { get: function () {
2335             return isObject$4(this) ? this[TYPED_ARRAY_TAG] : undefined;
2336           } });
2337           for (NAME$1 in TypedArrayConstructorsList) if (global$2[NAME$1]) {
2338             createNonEnumerableProperty(global$2[NAME$1], TYPED_ARRAY_TAG, NAME$1);
2339           }
2340         }
2341
2342         var arrayBufferViewCore = {
2343           NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS$2,
2344           TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQIRED && TYPED_ARRAY_TAG,
2345           aTypedArray: aTypedArray$m,
2346           aTypedArrayConstructor: aTypedArrayConstructor$4,
2347           exportTypedArrayMethod: exportTypedArrayMethod$n,
2348           exportTypedArrayStaticMethod: exportTypedArrayStaticMethod$1,
2349           isView: isView,
2350           isTypedArray: isTypedArray,
2351           TypedArray: TypedArray,
2352           TypedArrayPrototype: TypedArrayPrototype
2353         };
2354
2355         var NATIVE_ARRAY_BUFFER_VIEWS$1 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
2356
2357         // `ArrayBuffer.isView` method
2358         // https://tc39.es/ecma262/#sec-arraybuffer.isview
2359         _export({ target: 'ArrayBuffer', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS$1 }, {
2360           isView: arrayBufferViewCore.isView
2361         });
2362
2363         var SPECIES$4 = wellKnownSymbol('species');
2364
2365         var setSpecies = function (CONSTRUCTOR_NAME) {
2366           var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
2367           var defineProperty = objectDefineProperty.f;
2368
2369           if (descriptors && Constructor && !Constructor[SPECIES$4]) {
2370             defineProperty(Constructor, SPECIES$4, {
2371               configurable: true,
2372               get: function () { return this; }
2373             });
2374           }
2375         };
2376
2377         var ARRAY_BUFFER = 'ArrayBuffer';
2378         var ArrayBuffer$2 = arrayBuffer[ARRAY_BUFFER];
2379         var NativeArrayBuffer = global$2[ARRAY_BUFFER];
2380
2381         // `ArrayBuffer` constructor
2382         // https://tc39.es/ecma262/#sec-arraybuffer-constructor
2383         _export({ global: true, forced: NativeArrayBuffer !== ArrayBuffer$2 }, {
2384           ArrayBuffer: ArrayBuffer$2
2385         });
2386
2387         setSpecies(ARRAY_BUFFER);
2388
2389         var arrayMethodIsStrict = function (METHOD_NAME, argument) {
2390           var method = [][METHOD_NAME];
2391           return !!method && fails(function () {
2392             // eslint-disable-next-line no-useless-call,no-throw-literal -- required for testing
2393             method.call(null, argument || function () { throw 1; }, 1);
2394           });
2395         };
2396
2397         /* eslint-disable es/no-array-prototype-indexof -- required for testing */
2398
2399         var $indexOf$1 = arrayIncludes.indexOf;
2400
2401
2402         var nativeIndexOf = [].indexOf;
2403
2404         var NEGATIVE_ZERO$1 = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
2405         var STRICT_METHOD$7 = arrayMethodIsStrict('indexOf');
2406
2407         // `Array.prototype.indexOf` method
2408         // https://tc39.es/ecma262/#sec-array.prototype.indexof
2409         _export({ target: 'Array', proto: true, forced: NEGATIVE_ZERO$1 || !STRICT_METHOD$7 }, {
2410           indexOf: function indexOf(searchElement /* , fromIndex = 0 */) {
2411             return NEGATIVE_ZERO$1
2412               // convert -0 to +0
2413               ? nativeIndexOf.apply(this, arguments) || 0
2414               : $indexOf$1(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
2415           }
2416         });
2417
2418         var SPECIES$3 = wellKnownSymbol('species');
2419
2420         var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
2421           // We can't use this feature detection in V8 since it causes
2422           // deoptimization and serious performance degradation
2423           // https://github.com/zloirock/core-js/issues/677
2424           return engineV8Version >= 51 || !fails(function () {
2425             var array = [];
2426             var constructor = array.constructor = {};
2427             constructor[SPECIES$3] = function () {
2428               return { foo: 1 };
2429             };
2430             return array[METHOD_NAME](Boolean).foo !== 1;
2431           });
2432         };
2433
2434         var $map$1 = arrayIteration.map;
2435
2436
2437         var HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport('map');
2438
2439         // `Array.prototype.map` method
2440         // https://tc39.es/ecma262/#sec-array.prototype.map
2441         // with adding support of @@species
2442         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$3 }, {
2443           map: function map(callbackfn /* , thisArg */) {
2444             return $map$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
2445           }
2446         });
2447
2448         var $forEach$1 = arrayIteration.forEach;
2449
2450
2451         var STRICT_METHOD$6 = arrayMethodIsStrict('forEach');
2452
2453         // `Array.prototype.forEach` method implementation
2454         // https://tc39.es/ecma262/#sec-array.prototype.foreach
2455         var arrayForEach = !STRICT_METHOD$6 ? function forEach(callbackfn /* , thisArg */) {
2456           return $forEach$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
2457         // eslint-disable-next-line es/no-array-prototype-foreach -- safe
2458         } : [].forEach;
2459
2460         // `Array.prototype.forEach` method
2461         // https://tc39.es/ecma262/#sec-array.prototype.foreach
2462         // eslint-disable-next-line es/no-array-prototype-foreach -- safe
2463         _export({ target: 'Array', proto: true, forced: [].forEach != arrayForEach }, {
2464           forEach: arrayForEach
2465         });
2466
2467         for (var COLLECTION_NAME in domIterables) {
2468           var Collection = global$2[COLLECTION_NAME];
2469           var CollectionPrototype = Collection && Collection.prototype;
2470           // some Chrome versions have non-configurable methods on DOMTokenList
2471           if (CollectionPrototype && CollectionPrototype.forEach !== arrayForEach) try {
2472             createNonEnumerableProperty(CollectionPrototype, 'forEach', arrayForEach);
2473           } catch (error) {
2474             CollectionPrototype.forEach = arrayForEach;
2475           }
2476         }
2477
2478         // `Array.isArray` method
2479         // https://tc39.es/ecma262/#sec-array.isarray
2480         _export({ target: 'Array', stat: true }, {
2481           isArray: isArray
2482         });
2483
2484         var getOwnPropertyNames$2 = objectGetOwnPropertyNamesExternal.f;
2485
2486         // eslint-disable-next-line es/no-object-getownpropertynames -- required for testing
2487         var FAILS_ON_PRIMITIVES$4 = fails(function () { return !Object.getOwnPropertyNames(1); });
2488
2489         // `Object.getOwnPropertyNames` method
2490         // https://tc39.es/ecma262/#sec-object.getownpropertynames
2491         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$4 }, {
2492           getOwnPropertyNames: getOwnPropertyNames$2
2493         });
2494
2495         var nativePromiseConstructor = global$2.Promise;
2496
2497         var ITERATOR$5 = wellKnownSymbol('iterator');
2498         var ArrayPrototype = Array.prototype;
2499
2500         // check on default Array iterator
2501         var isArrayIteratorMethod = function (it) {
2502           return it !== undefined && (iterators.Array === it || ArrayPrototype[ITERATOR$5] === it);
2503         };
2504
2505         var ITERATOR$4 = wellKnownSymbol('iterator');
2506
2507         var getIteratorMethod = function (it) {
2508           if (it != undefined) return it[ITERATOR$4]
2509             || it['@@iterator']
2510             || iterators[classof(it)];
2511         };
2512
2513         var iteratorClose = function (iterator) {
2514           var returnMethod = iterator['return'];
2515           if (returnMethod !== undefined) {
2516             return anObject(returnMethod.call(iterator)).value;
2517           }
2518         };
2519
2520         var Result = function (stopped, result) {
2521           this.stopped = stopped;
2522           this.result = result;
2523         };
2524
2525         var iterate = function (iterable, unboundFunction, options) {
2526           var that = options && options.that;
2527           var AS_ENTRIES = !!(options && options.AS_ENTRIES);
2528           var IS_ITERATOR = !!(options && options.IS_ITERATOR);
2529           var INTERRUPTED = !!(options && options.INTERRUPTED);
2530           var fn = functionBindContext(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
2531           var iterator, iterFn, index, length, result, next, step;
2532
2533           var stop = function (condition) {
2534             if (iterator) iteratorClose(iterator);
2535             return new Result(true, condition);
2536           };
2537
2538           var callFn = function (value) {
2539             if (AS_ENTRIES) {
2540               anObject(value);
2541               return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
2542             } return INTERRUPTED ? fn(value, stop) : fn(value);
2543           };
2544
2545           if (IS_ITERATOR) {
2546             iterator = iterable;
2547           } else {
2548             iterFn = getIteratorMethod(iterable);
2549             if (typeof iterFn != 'function') throw TypeError('Target is not iterable');
2550             // optimisation for array iterators
2551             if (isArrayIteratorMethod(iterFn)) {
2552               for (index = 0, length = toLength(iterable.length); length > index; index++) {
2553                 result = callFn(iterable[index]);
2554                 if (result && result instanceof Result) return result;
2555               } return new Result(false);
2556             }
2557             iterator = iterFn.call(iterable);
2558           }
2559
2560           next = iterator.next;
2561           while (!(step = next.call(iterator)).done) {
2562             try {
2563               result = callFn(step.value);
2564             } catch (error) {
2565               iteratorClose(iterator);
2566               throw error;
2567             }
2568             if (typeof result == 'object' && result && result instanceof Result) return result;
2569           } return new Result(false);
2570         };
2571
2572         var ITERATOR$3 = wellKnownSymbol('iterator');
2573         var SAFE_CLOSING = false;
2574
2575         try {
2576           var called = 0;
2577           var iteratorWithReturn = {
2578             next: function () {
2579               return { done: !!called++ };
2580             },
2581             'return': function () {
2582               SAFE_CLOSING = true;
2583             }
2584           };
2585           iteratorWithReturn[ITERATOR$3] = function () {
2586             return this;
2587           };
2588           // eslint-disable-next-line es/no-array-from, no-throw-literal -- required for testing
2589           Array.from(iteratorWithReturn, function () { throw 2; });
2590         } catch (error) { /* empty */ }
2591
2592         var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
2593           if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
2594           var ITERATION_SUPPORT = false;
2595           try {
2596             var object = {};
2597             object[ITERATOR$3] = function () {
2598               return {
2599                 next: function () {
2600                   return { done: ITERATION_SUPPORT = true };
2601                 }
2602               };
2603             };
2604             exec(object);
2605           } catch (error) { /* empty */ }
2606           return ITERATION_SUPPORT;
2607         };
2608
2609         var engineIsIos = /(?:iphone|ipod|ipad).*applewebkit/i.test(engineUserAgent);
2610
2611         var engineIsNode = classofRaw(global$2.process) == 'process';
2612
2613         var location$1 = global$2.location;
2614         var set$2 = global$2.setImmediate;
2615         var clear = global$2.clearImmediate;
2616         var process$3 = global$2.process;
2617         var MessageChannel = global$2.MessageChannel;
2618         var Dispatch$1 = global$2.Dispatch;
2619         var counter = 0;
2620         var queue = {};
2621         var ONREADYSTATECHANGE = 'onreadystatechange';
2622         var defer, channel, port;
2623
2624         var run = function (id) {
2625           // eslint-disable-next-line no-prototype-builtins -- safe
2626           if (queue.hasOwnProperty(id)) {
2627             var fn = queue[id];
2628             delete queue[id];
2629             fn();
2630           }
2631         };
2632
2633         var runner = function (id) {
2634           return function () {
2635             run(id);
2636           };
2637         };
2638
2639         var listener = function (event) {
2640           run(event.data);
2641         };
2642
2643         var post = function (id) {
2644           // old engines have not location.origin
2645           global$2.postMessage(id + '', location$1.protocol + '//' + location$1.host);
2646         };
2647
2648         // Node.js 0.9+ & IE10+ has setImmediate, otherwise:
2649         if (!set$2 || !clear) {
2650           set$2 = function setImmediate(fn) {
2651             var args = [];
2652             var i = 1;
2653             while (arguments.length > i) args.push(arguments[i++]);
2654             queue[++counter] = function () {
2655               // eslint-disable-next-line no-new-func -- spec requirement
2656               (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
2657             };
2658             defer(counter);
2659             return counter;
2660           };
2661           clear = function clearImmediate(id) {
2662             delete queue[id];
2663           };
2664           // Node.js 0.8-
2665           if (engineIsNode) {
2666             defer = function (id) {
2667               process$3.nextTick(runner(id));
2668             };
2669           // Sphere (JS game engine) Dispatch API
2670           } else if (Dispatch$1 && Dispatch$1.now) {
2671             defer = function (id) {
2672               Dispatch$1.now(runner(id));
2673             };
2674           // Browsers with MessageChannel, includes WebWorkers
2675           // except iOS - https://github.com/zloirock/core-js/issues/624
2676           } else if (MessageChannel && !engineIsIos) {
2677             channel = new MessageChannel();
2678             port = channel.port2;
2679             channel.port1.onmessage = listener;
2680             defer = functionBindContext(port.postMessage, port, 1);
2681           // Browsers with postMessage, skip WebWorkers
2682           // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
2683           } else if (
2684             global$2.addEventListener &&
2685             typeof postMessage == 'function' &&
2686             !global$2.importScripts &&
2687             location$1 && location$1.protocol !== 'file:' &&
2688             !fails(post)
2689           ) {
2690             defer = post;
2691             global$2.addEventListener('message', listener, false);
2692           // IE8-
2693           } else if (ONREADYSTATECHANGE in documentCreateElement('script')) {
2694             defer = function (id) {
2695               html.appendChild(documentCreateElement('script'))[ONREADYSTATECHANGE] = function () {
2696                 html.removeChild(this);
2697                 run(id);
2698               };
2699             };
2700           // Rest old browsers
2701           } else {
2702             defer = function (id) {
2703               setTimeout(runner(id), 0);
2704             };
2705           }
2706         }
2707
2708         var task$1 = {
2709           set: set$2,
2710           clear: clear
2711         };
2712
2713         var engineIsWebosWebkit = /web0s(?!.*chrome)/i.test(engineUserAgent);
2714
2715         var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
2716         var macrotask = task$1.set;
2717
2718
2719
2720
2721         var MutationObserver = global$2.MutationObserver || global$2.WebKitMutationObserver;
2722         var document$2 = global$2.document;
2723         var process$2 = global$2.process;
2724         var Promise$1 = global$2.Promise;
2725         // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
2726         var queueMicrotaskDescriptor = getOwnPropertyDescriptor$3(global$2, 'queueMicrotask');
2727         var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
2728
2729         var flush, head, last, notify$1, toggle, node, promise, then;
2730
2731         // modern engines have queueMicrotask method
2732         if (!queueMicrotask) {
2733           flush = function () {
2734             var parent, fn;
2735             if (engineIsNode && (parent = process$2.domain)) parent.exit();
2736             while (head) {
2737               fn = head.fn;
2738               head = head.next;
2739               try {
2740                 fn();
2741               } catch (error) {
2742                 if (head) notify$1();
2743                 else last = undefined;
2744                 throw error;
2745               }
2746             } last = undefined;
2747             if (parent) parent.enter();
2748           };
2749
2750           // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
2751           // also except WebOS Webkit https://github.com/zloirock/core-js/issues/898
2752           if (!engineIsIos && !engineIsNode && !engineIsWebosWebkit && MutationObserver && document$2) {
2753             toggle = true;
2754             node = document$2.createTextNode('');
2755             new MutationObserver(flush).observe(node, { characterData: true });
2756             notify$1 = function () {
2757               node.data = toggle = !toggle;
2758             };
2759           // environments with maybe non-completely correct, but existent Promise
2760           } else if (Promise$1 && Promise$1.resolve) {
2761             // Promise.resolve without an argument throws an error in LG WebOS 2
2762             promise = Promise$1.resolve(undefined);
2763             // workaround of WebKit ~ iOS Safari 10.1 bug
2764             promise.constructor = Promise$1;
2765             then = promise.then;
2766             notify$1 = function () {
2767               then.call(promise, flush);
2768             };
2769           // Node.js without promises
2770           } else if (engineIsNode) {
2771             notify$1 = function () {
2772               process$2.nextTick(flush);
2773             };
2774           // for other environments - macrotask based on:
2775           // - setImmediate
2776           // - MessageChannel
2777           // - window.postMessag
2778           // - onreadystatechange
2779           // - setTimeout
2780           } else {
2781             notify$1 = function () {
2782               // strange IE + webpack dev server bug - use .call(global)
2783               macrotask.call(global$2, flush);
2784             };
2785           }
2786         }
2787
2788         var microtask = queueMicrotask || function (fn) {
2789           var task = { fn: fn, next: undefined };
2790           if (last) last.next = task;
2791           if (!head) {
2792             head = task;
2793             notify$1();
2794           } last = task;
2795         };
2796
2797         var PromiseCapability = function (C) {
2798           var resolve, reject;
2799           this.promise = new C(function ($$resolve, $$reject) {
2800             if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');
2801             resolve = $$resolve;
2802             reject = $$reject;
2803           });
2804           this.resolve = aFunction(resolve);
2805           this.reject = aFunction(reject);
2806         };
2807
2808         // `NewPromiseCapability` abstract operation
2809         // https://tc39.es/ecma262/#sec-newpromisecapability
2810         var f = function (C) {
2811           return new PromiseCapability(C);
2812         };
2813
2814         var newPromiseCapability$1 = {
2815                 f: f
2816         };
2817
2818         var promiseResolve = function (C, x) {
2819           anObject(C);
2820           if (isObject$4(x) && x.constructor === C) return x;
2821           var promiseCapability = newPromiseCapability$1.f(C);
2822           var resolve = promiseCapability.resolve;
2823           resolve(x);
2824           return promiseCapability.promise;
2825         };
2826
2827         var hostReportErrors = function (a, b) {
2828           var console = global$2.console;
2829           if (console && console.error) {
2830             arguments.length === 1 ? console.error(a) : console.error(a, b);
2831           }
2832         };
2833
2834         var perform = function (exec) {
2835           try {
2836             return { error: false, value: exec() };
2837           } catch (error) {
2838             return { error: true, value: error };
2839           }
2840         };
2841
2842         var engineIsBrowser = typeof window == 'object';
2843
2844         var task = task$1.set;
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857         var SPECIES$2 = wellKnownSymbol('species');
2858         var PROMISE = 'Promise';
2859         var getInternalState$1 = internalState.get;
2860         var setInternalState$3 = internalState.set;
2861         var getInternalPromiseState = internalState.getterFor(PROMISE);
2862         var NativePromisePrototype = nativePromiseConstructor && nativePromiseConstructor.prototype;
2863         var PromiseConstructor = nativePromiseConstructor;
2864         var PromiseConstructorPrototype = NativePromisePrototype;
2865         var TypeError$1 = global$2.TypeError;
2866         var document$1 = global$2.document;
2867         var process$1 = global$2.process;
2868         var newPromiseCapability = newPromiseCapability$1.f;
2869         var newGenericPromiseCapability = newPromiseCapability;
2870         var DISPATCH_EVENT = !!(document$1 && document$1.createEvent && global$2.dispatchEvent);
2871         var NATIVE_REJECTION_EVENT = typeof PromiseRejectionEvent == 'function';
2872         var UNHANDLED_REJECTION = 'unhandledrejection';
2873         var REJECTION_HANDLED = 'rejectionhandled';
2874         var PENDING = 0;
2875         var FULFILLED = 1;
2876         var REJECTED = 2;
2877         var HANDLED = 1;
2878         var UNHANDLED = 2;
2879         var SUBCLASSING = false;
2880         var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
2881
2882         var FORCED$f = isForced_1(PROMISE, function () {
2883           var PROMISE_CONSTRUCTOR_SOURCE = inspectSource(PromiseConstructor);
2884           var GLOBAL_CORE_JS_PROMISE = PROMISE_CONSTRUCTOR_SOURCE !== String(PromiseConstructor);
2885           // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
2886           // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
2887           // We can't detect it synchronously, so just check versions
2888           if (!GLOBAL_CORE_JS_PROMISE && engineV8Version === 66) return true;
2889           // We can't use @@species feature detection in V8 since it causes
2890           // deoptimization and performance degradation
2891           // https://github.com/zloirock/core-js/issues/679
2892           if (engineV8Version >= 51 && /native code/.test(PROMISE_CONSTRUCTOR_SOURCE)) return false;
2893           // Detect correctness of subclassing with @@species support
2894           var promise = new PromiseConstructor(function (resolve) { resolve(1); });
2895           var FakePromise = function (exec) {
2896             exec(function () { /* empty */ }, function () { /* empty */ });
2897           };
2898           var constructor = promise.constructor = {};
2899           constructor[SPECIES$2] = FakePromise;
2900           SUBCLASSING = promise.then(function () { /* empty */ }) instanceof FakePromise;
2901           if (!SUBCLASSING) return true;
2902           // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
2903           return !GLOBAL_CORE_JS_PROMISE && engineIsBrowser && !NATIVE_REJECTION_EVENT;
2904         });
2905
2906         var INCORRECT_ITERATION$1 = FORCED$f || !checkCorrectnessOfIteration(function (iterable) {
2907           PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });
2908         });
2909
2910         // helpers
2911         var isThenable = function (it) {
2912           var then;
2913           return isObject$4(it) && typeof (then = it.then) == 'function' ? then : false;
2914         };
2915
2916         var notify = function (state, isReject) {
2917           if (state.notified) return;
2918           state.notified = true;
2919           var chain = state.reactions;
2920           microtask(function () {
2921             var value = state.value;
2922             var ok = state.state == FULFILLED;
2923             var index = 0;
2924             // variable length - can't use forEach
2925             while (chain.length > index) {
2926               var reaction = chain[index++];
2927               var handler = ok ? reaction.ok : reaction.fail;
2928               var resolve = reaction.resolve;
2929               var reject = reaction.reject;
2930               var domain = reaction.domain;
2931               var result, then, exited;
2932               try {
2933                 if (handler) {
2934                   if (!ok) {
2935                     if (state.rejection === UNHANDLED) onHandleUnhandled(state);
2936                     state.rejection = HANDLED;
2937                   }
2938                   if (handler === true) result = value;
2939                   else {
2940                     if (domain) domain.enter();
2941                     result = handler(value); // can throw
2942                     if (domain) {
2943                       domain.exit();
2944                       exited = true;
2945                     }
2946                   }
2947                   if (result === reaction.promise) {
2948                     reject(TypeError$1('Promise-chain cycle'));
2949                   } else if (then = isThenable(result)) {
2950                     then.call(result, resolve, reject);
2951                   } else resolve(result);
2952                 } else reject(value);
2953               } catch (error) {
2954                 if (domain && !exited) domain.exit();
2955                 reject(error);
2956               }
2957             }
2958             state.reactions = [];
2959             state.notified = false;
2960             if (isReject && !state.rejection) onUnhandled(state);
2961           });
2962         };
2963
2964         var dispatchEvent$1 = function (name, promise, reason) {
2965           var event, handler;
2966           if (DISPATCH_EVENT) {
2967             event = document$1.createEvent('Event');
2968             event.promise = promise;
2969             event.reason = reason;
2970             event.initEvent(name, false, true);
2971             global$2.dispatchEvent(event);
2972           } else event = { promise: promise, reason: reason };
2973           if (!NATIVE_REJECTION_EVENT && (handler = global$2['on' + name])) handler(event);
2974           else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
2975         };
2976
2977         var onUnhandled = function (state) {
2978           task.call(global$2, function () {
2979             var promise = state.facade;
2980             var value = state.value;
2981             var IS_UNHANDLED = isUnhandled(state);
2982             var result;
2983             if (IS_UNHANDLED) {
2984               result = perform(function () {
2985                 if (engineIsNode) {
2986                   process$1.emit('unhandledRejection', value, promise);
2987                 } else dispatchEvent$1(UNHANDLED_REJECTION, promise, value);
2988               });
2989               // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
2990               state.rejection = engineIsNode || isUnhandled(state) ? UNHANDLED : HANDLED;
2991               if (result.error) throw result.value;
2992             }
2993           });
2994         };
2995
2996         var isUnhandled = function (state) {
2997           return state.rejection !== HANDLED && !state.parent;
2998         };
2999
3000         var onHandleUnhandled = function (state) {
3001           task.call(global$2, function () {
3002             var promise = state.facade;
3003             if (engineIsNode) {
3004               process$1.emit('rejectionHandled', promise);
3005             } else dispatchEvent$1(REJECTION_HANDLED, promise, state.value);
3006           });
3007         };
3008
3009         var bind$2 = function (fn, state, unwrap) {
3010           return function (value) {
3011             fn(state, value, unwrap);
3012           };
3013         };
3014
3015         var internalReject = function (state, value, unwrap) {
3016           if (state.done) return;
3017           state.done = true;
3018           if (unwrap) state = unwrap;
3019           state.value = value;
3020           state.state = REJECTED;
3021           notify(state, true);
3022         };
3023
3024         var internalResolve = function (state, value, unwrap) {
3025           if (state.done) return;
3026           state.done = true;
3027           if (unwrap) state = unwrap;
3028           try {
3029             if (state.facade === value) throw TypeError$1("Promise can't be resolved itself");
3030             var then = isThenable(value);
3031             if (then) {
3032               microtask(function () {
3033                 var wrapper = { done: false };
3034                 try {
3035                   then.call(value,
3036                     bind$2(internalResolve, wrapper, state),
3037                     bind$2(internalReject, wrapper, state)
3038                   );
3039                 } catch (error) {
3040                   internalReject(wrapper, error, state);
3041                 }
3042               });
3043             } else {
3044               state.value = value;
3045               state.state = FULFILLED;
3046               notify(state, false);
3047             }
3048           } catch (error) {
3049             internalReject({ done: false }, error, state);
3050           }
3051         };
3052
3053         // constructor polyfill
3054         if (FORCED$f) {
3055           // 25.4.3.1 Promise(executor)
3056           PromiseConstructor = function Promise(executor) {
3057             anInstance(this, PromiseConstructor, PROMISE);
3058             aFunction(executor);
3059             Internal.call(this);
3060             var state = getInternalState$1(this);
3061             try {
3062               executor(bind$2(internalResolve, state), bind$2(internalReject, state));
3063             } catch (error) {
3064               internalReject(state, error);
3065             }
3066           };
3067           PromiseConstructorPrototype = PromiseConstructor.prototype;
3068           // eslint-disable-next-line no-unused-vars -- required for `.length`
3069           Internal = function Promise(executor) {
3070             setInternalState$3(this, {
3071               type: PROMISE,
3072               done: false,
3073               notified: false,
3074               parent: false,
3075               reactions: [],
3076               rejection: false,
3077               state: PENDING,
3078               value: undefined
3079             });
3080           };
3081           Internal.prototype = redefineAll(PromiseConstructorPrototype, {
3082             // `Promise.prototype.then` method
3083             // https://tc39.es/ecma262/#sec-promise.prototype.then
3084             then: function then(onFulfilled, onRejected) {
3085               var state = getInternalPromiseState(this);
3086               var reaction = newPromiseCapability(speciesConstructor(this, PromiseConstructor));
3087               reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
3088               reaction.fail = typeof onRejected == 'function' && onRejected;
3089               reaction.domain = engineIsNode ? process$1.domain : undefined;
3090               state.parent = true;
3091               state.reactions.push(reaction);
3092               if (state.state != PENDING) notify(state, false);
3093               return reaction.promise;
3094             },
3095             // `Promise.prototype.catch` method
3096             // https://tc39.es/ecma262/#sec-promise.prototype.catch
3097             'catch': function (onRejected) {
3098               return this.then(undefined, onRejected);
3099             }
3100           });
3101           OwnPromiseCapability = function () {
3102             var promise = new Internal();
3103             var state = getInternalState$1(promise);
3104             this.promise = promise;
3105             this.resolve = bind$2(internalResolve, state);
3106             this.reject = bind$2(internalReject, state);
3107           };
3108           newPromiseCapability$1.f = newPromiseCapability = function (C) {
3109             return C === PromiseConstructor || C === PromiseWrapper
3110               ? new OwnPromiseCapability(C)
3111               : newGenericPromiseCapability(C);
3112           };
3113
3114           if (typeof nativePromiseConstructor == 'function' && NativePromisePrototype !== Object.prototype) {
3115             nativeThen = NativePromisePrototype.then;
3116
3117             if (!SUBCLASSING) {
3118               // make `Promise#then` return a polyfilled `Promise` for native promise-based APIs
3119               redefine(NativePromisePrototype, 'then', function then(onFulfilled, onRejected) {
3120                 var that = this;
3121                 return new PromiseConstructor(function (resolve, reject) {
3122                   nativeThen.call(that, resolve, reject);
3123                 }).then(onFulfilled, onRejected);
3124               // https://github.com/zloirock/core-js/issues/640
3125               }, { unsafe: true });
3126
3127               // makes sure that native promise-based APIs `Promise#catch` properly works with patched `Promise#then`
3128               redefine(NativePromisePrototype, 'catch', PromiseConstructorPrototype['catch'], { unsafe: true });
3129             }
3130
3131             // make `.constructor === Promise` work for native promise-based APIs
3132             try {
3133               delete NativePromisePrototype.constructor;
3134             } catch (error) { /* empty */ }
3135
3136             // make `instanceof Promise` work for native promise-based APIs
3137             if (objectSetPrototypeOf) {
3138               objectSetPrototypeOf(NativePromisePrototype, PromiseConstructorPrototype);
3139             }
3140           }
3141         }
3142
3143         _export({ global: true, wrap: true, forced: FORCED$f }, {
3144           Promise: PromiseConstructor
3145         });
3146
3147         setToStringTag(PromiseConstructor, PROMISE, false);
3148         setSpecies(PROMISE);
3149
3150         PromiseWrapper = getBuiltIn(PROMISE);
3151
3152         // statics
3153         _export({ target: PROMISE, stat: true, forced: FORCED$f }, {
3154           // `Promise.reject` method
3155           // https://tc39.es/ecma262/#sec-promise.reject
3156           reject: function reject(r) {
3157             var capability = newPromiseCapability(this);
3158             capability.reject.call(undefined, r);
3159             return capability.promise;
3160           }
3161         });
3162
3163         _export({ target: PROMISE, stat: true, forced: FORCED$f }, {
3164           // `Promise.resolve` method
3165           // https://tc39.es/ecma262/#sec-promise.resolve
3166           resolve: function resolve(x) {
3167             return promiseResolve(this, x);
3168           }
3169         });
3170
3171         _export({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION$1 }, {
3172           // `Promise.all` method
3173           // https://tc39.es/ecma262/#sec-promise.all
3174           all: function all(iterable) {
3175             var C = this;
3176             var capability = newPromiseCapability(C);
3177             var resolve = capability.resolve;
3178             var reject = capability.reject;
3179             var result = perform(function () {
3180               var $promiseResolve = aFunction(C.resolve);
3181               var values = [];
3182               var counter = 0;
3183               var remaining = 1;
3184               iterate(iterable, function (promise) {
3185                 var index = counter++;
3186                 var alreadyCalled = false;
3187                 values.push(undefined);
3188                 remaining++;
3189                 $promiseResolve.call(C, promise).then(function (value) {
3190                   if (alreadyCalled) return;
3191                   alreadyCalled = true;
3192                   values[index] = value;
3193                   --remaining || resolve(values);
3194                 }, reject);
3195               });
3196               --remaining || resolve(values);
3197             });
3198             if (result.error) reject(result.value);
3199             return capability.promise;
3200           },
3201           // `Promise.race` method
3202           // https://tc39.es/ecma262/#sec-promise.race
3203           race: function race(iterable) {
3204             var C = this;
3205             var capability = newPromiseCapability(C);
3206             var reject = capability.reject;
3207             var result = perform(function () {
3208               var $promiseResolve = aFunction(C.resolve);
3209               iterate(iterable, function (promise) {
3210                 $promiseResolve.call(C, promise).then(capability.resolve, reject);
3211               });
3212             });
3213             if (result.error) reject(result.value);
3214             return capability.promise;
3215           }
3216         });
3217
3218         /* eslint-disable no-new -- required for testing */
3219
3220         var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3221
3222         var ArrayBuffer$1 = global$2.ArrayBuffer;
3223         var Int8Array$2 = global$2.Int8Array;
3224
3225         var typedArrayConstructorsRequireWrappers = !NATIVE_ARRAY_BUFFER_VIEWS || !fails(function () {
3226           Int8Array$2(1);
3227         }) || !fails(function () {
3228           new Int8Array$2(-1);
3229         }) || !checkCorrectnessOfIteration(function (iterable) {
3230           new Int8Array$2();
3231           new Int8Array$2(null);
3232           new Int8Array$2(1.5);
3233           new Int8Array$2(iterable);
3234         }, true) || fails(function () {
3235           // Safari (11+) bug - a reason why even Safari 13 should load a typed array polyfill
3236           return new Int8Array$2(new ArrayBuffer$1(2), 1, undefined).length !== 1;
3237         });
3238
3239         var toPositiveInteger = function (it) {
3240           var result = toInteger(it);
3241           if (result < 0) throw RangeError("The argument can't be less than 0");
3242           return result;
3243         };
3244
3245         var toOffset = function (it, BYTES) {
3246           var offset = toPositiveInteger(it);
3247           if (offset % BYTES) throw RangeError('Wrong offset');
3248           return offset;
3249         };
3250
3251         var aTypedArrayConstructor$3 = arrayBufferViewCore.aTypedArrayConstructor;
3252
3253         var typedArrayFrom = function from(source /* , mapfn, thisArg */) {
3254           var O = toObject(source);
3255           var argumentsLength = arguments.length;
3256           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
3257           var mapping = mapfn !== undefined;
3258           var iteratorMethod = getIteratorMethod(O);
3259           var i, length, result, step, iterator, next;
3260           if (iteratorMethod != undefined && !isArrayIteratorMethod(iteratorMethod)) {
3261             iterator = iteratorMethod.call(O);
3262             next = iterator.next;
3263             O = [];
3264             while (!(step = next.call(iterator)).done) {
3265               O.push(step.value);
3266             }
3267           }
3268           if (mapping && argumentsLength > 2) {
3269             mapfn = functionBindContext(mapfn, arguments[2], 2);
3270           }
3271           length = toLength(O.length);
3272           result = new (aTypedArrayConstructor$3(this))(length);
3273           for (i = 0; length > i; i++) {
3274             result[i] = mapping ? mapfn(O[i], i) : O[i];
3275           }
3276           return result;
3277         };
3278
3279         // makes subclassing work correct for wrapped built-ins
3280         var inheritIfRequired = function ($this, dummy, Wrapper) {
3281           var NewTarget, NewTargetPrototype;
3282           if (
3283             // it can work only with native `setPrototypeOf`
3284             objectSetPrototypeOf &&
3285             // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
3286             typeof (NewTarget = dummy.constructor) == 'function' &&
3287             NewTarget !== Wrapper &&
3288             isObject$4(NewTargetPrototype = NewTarget.prototype) &&
3289             NewTargetPrototype !== Wrapper.prototype
3290           ) objectSetPrototypeOf($this, NewTargetPrototype);
3291           return $this;
3292         };
3293
3294         var typedArrayConstructor = createCommonjsModule(function (module) {
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313         var getOwnPropertyNames = objectGetOwnPropertyNames.f;
3314
3315         var forEach = arrayIteration.forEach;
3316
3317
3318
3319
3320
3321
3322         var getInternalState = internalState.get;
3323         var setInternalState = internalState.set;
3324         var nativeDefineProperty = objectDefineProperty.f;
3325         var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
3326         var round = Math.round;
3327         var RangeError = global$2.RangeError;
3328         var ArrayBuffer = arrayBuffer.ArrayBuffer;
3329         var DataView = arrayBuffer.DataView;
3330         var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3331         var TYPED_ARRAY_TAG = arrayBufferViewCore.TYPED_ARRAY_TAG;
3332         var TypedArray = arrayBufferViewCore.TypedArray;
3333         var TypedArrayPrototype = arrayBufferViewCore.TypedArrayPrototype;
3334         var aTypedArrayConstructor = arrayBufferViewCore.aTypedArrayConstructor;
3335         var isTypedArray = arrayBufferViewCore.isTypedArray;
3336         var BYTES_PER_ELEMENT = 'BYTES_PER_ELEMENT';
3337         var WRONG_LENGTH = 'Wrong length';
3338
3339         var fromList = function (C, list) {
3340           var index = 0;
3341           var length = list.length;
3342           var result = new (aTypedArrayConstructor(C))(length);
3343           while (length > index) result[index] = list[index++];
3344           return result;
3345         };
3346
3347         var addGetter = function (it, key) {
3348           nativeDefineProperty(it, key, { get: function () {
3349             return getInternalState(this)[key];
3350           } });
3351         };
3352
3353         var isArrayBuffer = function (it) {
3354           var klass;
3355           return it instanceof ArrayBuffer || (klass = classof(it)) == 'ArrayBuffer' || klass == 'SharedArrayBuffer';
3356         };
3357
3358         var isTypedArrayIndex = function (target, key) {
3359           return isTypedArray(target)
3360             && typeof key != 'symbol'
3361             && key in target
3362             && String(+key) == String(key);
3363         };
3364
3365         var wrappedGetOwnPropertyDescriptor = function getOwnPropertyDescriptor(target, key) {
3366           return isTypedArrayIndex(target, key = toPrimitive(key, true))
3367             ? createPropertyDescriptor(2, target[key])
3368             : nativeGetOwnPropertyDescriptor(target, key);
3369         };
3370
3371         var wrappedDefineProperty = function defineProperty(target, key, descriptor) {
3372           if (isTypedArrayIndex(target, key = toPrimitive(key, true))
3373             && isObject$4(descriptor)
3374             && has$1(descriptor, 'value')
3375             && !has$1(descriptor, 'get')
3376             && !has$1(descriptor, 'set')
3377             // TODO: add validation descriptor w/o calling accessors
3378             && !descriptor.configurable
3379             && (!has$1(descriptor, 'writable') || descriptor.writable)
3380             && (!has$1(descriptor, 'enumerable') || descriptor.enumerable)
3381           ) {
3382             target[key] = descriptor.value;
3383             return target;
3384           } return nativeDefineProperty(target, key, descriptor);
3385         };
3386
3387         if (descriptors) {
3388           if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3389             objectGetOwnPropertyDescriptor.f = wrappedGetOwnPropertyDescriptor;
3390             objectDefineProperty.f = wrappedDefineProperty;
3391             addGetter(TypedArrayPrototype, 'buffer');
3392             addGetter(TypedArrayPrototype, 'byteOffset');
3393             addGetter(TypedArrayPrototype, 'byteLength');
3394             addGetter(TypedArrayPrototype, 'length');
3395           }
3396
3397           _export({ target: 'Object', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS }, {
3398             getOwnPropertyDescriptor: wrappedGetOwnPropertyDescriptor,
3399             defineProperty: wrappedDefineProperty
3400           });
3401
3402           module.exports = function (TYPE, wrapper, CLAMPED) {
3403             var BYTES = TYPE.match(/\d+$/)[0] / 8;
3404             var CONSTRUCTOR_NAME = TYPE + (CLAMPED ? 'Clamped' : '') + 'Array';
3405             var GETTER = 'get' + TYPE;
3406             var SETTER = 'set' + TYPE;
3407             var NativeTypedArrayConstructor = global$2[CONSTRUCTOR_NAME];
3408             var TypedArrayConstructor = NativeTypedArrayConstructor;
3409             var TypedArrayConstructorPrototype = TypedArrayConstructor && TypedArrayConstructor.prototype;
3410             var exported = {};
3411
3412             var getter = function (that, index) {
3413               var data = getInternalState(that);
3414               return data.view[GETTER](index * BYTES + data.byteOffset, true);
3415             };
3416
3417             var setter = function (that, index, value) {
3418               var data = getInternalState(that);
3419               if (CLAMPED) value = (value = round(value)) < 0 ? 0 : value > 0xFF ? 0xFF : value & 0xFF;
3420               data.view[SETTER](index * BYTES + data.byteOffset, value, true);
3421             };
3422
3423             var addElement = function (that, index) {
3424               nativeDefineProperty(that, index, {
3425                 get: function () {
3426                   return getter(this, index);
3427                 },
3428                 set: function (value) {
3429                   return setter(this, index, value);
3430                 },
3431                 enumerable: true
3432               });
3433             };
3434
3435             if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3436               TypedArrayConstructor = wrapper(function (that, data, offset, $length) {
3437                 anInstance(that, TypedArrayConstructor, CONSTRUCTOR_NAME);
3438                 var index = 0;
3439                 var byteOffset = 0;
3440                 var buffer, byteLength, length;
3441                 if (!isObject$4(data)) {
3442                   length = toIndex(data);
3443                   byteLength = length * BYTES;
3444                   buffer = new ArrayBuffer(byteLength);
3445                 } else if (isArrayBuffer(data)) {
3446                   buffer = data;
3447                   byteOffset = toOffset(offset, BYTES);
3448                   var $len = data.byteLength;
3449                   if ($length === undefined) {
3450                     if ($len % BYTES) throw RangeError(WRONG_LENGTH);
3451                     byteLength = $len - byteOffset;
3452                     if (byteLength < 0) throw RangeError(WRONG_LENGTH);
3453                   } else {
3454                     byteLength = toLength($length) * BYTES;
3455                     if (byteLength + byteOffset > $len) throw RangeError(WRONG_LENGTH);
3456                   }
3457                   length = byteLength / BYTES;
3458                 } else if (isTypedArray(data)) {
3459                   return fromList(TypedArrayConstructor, data);
3460                 } else {
3461                   return typedArrayFrom.call(TypedArrayConstructor, data);
3462                 }
3463                 setInternalState(that, {
3464                   buffer: buffer,
3465                   byteOffset: byteOffset,
3466                   byteLength: byteLength,
3467                   length: length,
3468                   view: new DataView(buffer)
3469                 });
3470                 while (index < length) addElement(that, index++);
3471               });
3472
3473               if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
3474               TypedArrayConstructorPrototype = TypedArrayConstructor.prototype = objectCreate(TypedArrayPrototype);
3475             } else if (typedArrayConstructorsRequireWrappers) {
3476               TypedArrayConstructor = wrapper(function (dummy, data, typedArrayOffset, $length) {
3477                 anInstance(dummy, TypedArrayConstructor, CONSTRUCTOR_NAME);
3478                 return inheritIfRequired(function () {
3479                   if (!isObject$4(data)) return new NativeTypedArrayConstructor(toIndex(data));
3480                   if (isArrayBuffer(data)) return $length !== undefined
3481                     ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES), $length)
3482                     : typedArrayOffset !== undefined
3483                       ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES))
3484                       : new NativeTypedArrayConstructor(data);
3485                   if (isTypedArray(data)) return fromList(TypedArrayConstructor, data);
3486                   return typedArrayFrom.call(TypedArrayConstructor, data);
3487                 }(), dummy, TypedArrayConstructor);
3488               });
3489
3490               if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
3491               forEach(getOwnPropertyNames(NativeTypedArrayConstructor), function (key) {
3492                 if (!(key in TypedArrayConstructor)) {
3493                   createNonEnumerableProperty(TypedArrayConstructor, key, NativeTypedArrayConstructor[key]);
3494                 }
3495               });
3496               TypedArrayConstructor.prototype = TypedArrayConstructorPrototype;
3497             }
3498
3499             if (TypedArrayConstructorPrototype.constructor !== TypedArrayConstructor) {
3500               createNonEnumerableProperty(TypedArrayConstructorPrototype, 'constructor', TypedArrayConstructor);
3501             }
3502
3503             if (TYPED_ARRAY_TAG) {
3504               createNonEnumerableProperty(TypedArrayConstructorPrototype, TYPED_ARRAY_TAG, CONSTRUCTOR_NAME);
3505             }
3506
3507             exported[CONSTRUCTOR_NAME] = TypedArrayConstructor;
3508
3509             _export({
3510               global: true, forced: TypedArrayConstructor != NativeTypedArrayConstructor, sham: !NATIVE_ARRAY_BUFFER_VIEWS
3511             }, exported);
3512
3513             if (!(BYTES_PER_ELEMENT in TypedArrayConstructor)) {
3514               createNonEnumerableProperty(TypedArrayConstructor, BYTES_PER_ELEMENT, BYTES);
3515             }
3516
3517             if (!(BYTES_PER_ELEMENT in TypedArrayConstructorPrototype)) {
3518               createNonEnumerableProperty(TypedArrayConstructorPrototype, BYTES_PER_ELEMENT, BYTES);
3519             }
3520
3521             setSpecies(CONSTRUCTOR_NAME);
3522           };
3523         } else module.exports = function () { /* empty */ };
3524         });
3525
3526         // `Uint8Array` constructor
3527         // https://tc39.es/ecma262/#sec-typedarray-objects
3528         typedArrayConstructor('Uint8', function (init) {
3529           return function Uint8Array(data, byteOffset, length) {
3530             return init(this, data, byteOffset, length);
3531           };
3532         });
3533
3534         var min$7 = Math.min;
3535
3536         // `Array.prototype.copyWithin` method implementation
3537         // https://tc39.es/ecma262/#sec-array.prototype.copywithin
3538         // eslint-disable-next-line es/no-array-prototype-copywithin -- safe
3539         var arrayCopyWithin = [].copyWithin || function copyWithin(target /* = 0 */, start /* = 0, end = @length */) {
3540           var O = toObject(this);
3541           var len = toLength(O.length);
3542           var to = toAbsoluteIndex(target, len);
3543           var from = toAbsoluteIndex(start, len);
3544           var end = arguments.length > 2 ? arguments[2] : undefined;
3545           var count = min$7((end === undefined ? len : toAbsoluteIndex(end, len)) - from, len - to);
3546           var inc = 1;
3547           if (from < to && to < from + count) {
3548             inc = -1;
3549             from += count - 1;
3550             to += count - 1;
3551           }
3552           while (count-- > 0) {
3553             if (from in O) O[to] = O[from];
3554             else delete O[to];
3555             to += inc;
3556             from += inc;
3557           } return O;
3558         };
3559
3560         var aTypedArray$l = arrayBufferViewCore.aTypedArray;
3561         var exportTypedArrayMethod$m = arrayBufferViewCore.exportTypedArrayMethod;
3562
3563         // `%TypedArray%.prototype.copyWithin` method
3564         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.copywithin
3565         exportTypedArrayMethod$m('copyWithin', function copyWithin(target, start /* , end */) {
3566           return arrayCopyWithin.call(aTypedArray$l(this), target, start, arguments.length > 2 ? arguments[2] : undefined);
3567         });
3568
3569         var $every$1 = arrayIteration.every;
3570
3571         var aTypedArray$k = arrayBufferViewCore.aTypedArray;
3572         var exportTypedArrayMethod$l = arrayBufferViewCore.exportTypedArrayMethod;
3573
3574         // `%TypedArray%.prototype.every` method
3575         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.every
3576         exportTypedArrayMethod$l('every', function every(callbackfn /* , thisArg */) {
3577           return $every$1(aTypedArray$k(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3578         });
3579
3580         var aTypedArray$j = arrayBufferViewCore.aTypedArray;
3581         var exportTypedArrayMethod$k = arrayBufferViewCore.exportTypedArrayMethod;
3582
3583         // `%TypedArray%.prototype.fill` method
3584         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.fill
3585         // eslint-disable-next-line no-unused-vars -- required for `.length`
3586         exportTypedArrayMethod$k('fill', function fill(value /* , start, end */) {
3587           return arrayFill.apply(aTypedArray$j(this), arguments);
3588         });
3589
3590         var aTypedArrayConstructor$2 = arrayBufferViewCore.aTypedArrayConstructor;
3591
3592
3593         var typedArrayFromSpeciesAndList = function (instance, list) {
3594           var C = speciesConstructor(instance, instance.constructor);
3595           var index = 0;
3596           var length = list.length;
3597           var result = new (aTypedArrayConstructor$2(C))(length);
3598           while (length > index) result[index] = list[index++];
3599           return result;
3600         };
3601
3602         var $filter$1 = arrayIteration.filter;
3603
3604
3605         var aTypedArray$i = arrayBufferViewCore.aTypedArray;
3606         var exportTypedArrayMethod$j = arrayBufferViewCore.exportTypedArrayMethod;
3607
3608         // `%TypedArray%.prototype.filter` method
3609         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.filter
3610         exportTypedArrayMethod$j('filter', function filter(callbackfn /* , thisArg */) {
3611           var list = $filter$1(aTypedArray$i(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3612           return typedArrayFromSpeciesAndList(this, list);
3613         });
3614
3615         var $find$1 = arrayIteration.find;
3616
3617         var aTypedArray$h = arrayBufferViewCore.aTypedArray;
3618         var exportTypedArrayMethod$i = arrayBufferViewCore.exportTypedArrayMethod;
3619
3620         // `%TypedArray%.prototype.find` method
3621         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.find
3622         exportTypedArrayMethod$i('find', function find(predicate /* , thisArg */) {
3623           return $find$1(aTypedArray$h(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
3624         });
3625
3626         var $findIndex$1 = arrayIteration.findIndex;
3627
3628         var aTypedArray$g = arrayBufferViewCore.aTypedArray;
3629         var exportTypedArrayMethod$h = arrayBufferViewCore.exportTypedArrayMethod;
3630
3631         // `%TypedArray%.prototype.findIndex` method
3632         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.findindex
3633         exportTypedArrayMethod$h('findIndex', function findIndex(predicate /* , thisArg */) {
3634           return $findIndex$1(aTypedArray$g(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
3635         });
3636
3637         var $forEach = arrayIteration.forEach;
3638
3639         var aTypedArray$f = arrayBufferViewCore.aTypedArray;
3640         var exportTypedArrayMethod$g = arrayBufferViewCore.exportTypedArrayMethod;
3641
3642         // `%TypedArray%.prototype.forEach` method
3643         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.foreach
3644         exportTypedArrayMethod$g('forEach', function forEach(callbackfn /* , thisArg */) {
3645           $forEach(aTypedArray$f(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3646         });
3647
3648         var $includes$1 = arrayIncludes.includes;
3649
3650         var aTypedArray$e = arrayBufferViewCore.aTypedArray;
3651         var exportTypedArrayMethod$f = arrayBufferViewCore.exportTypedArrayMethod;
3652
3653         // `%TypedArray%.prototype.includes` method
3654         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.includes
3655         exportTypedArrayMethod$f('includes', function includes(searchElement /* , fromIndex */) {
3656           return $includes$1(aTypedArray$e(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
3657         });
3658
3659         var $indexOf = arrayIncludes.indexOf;
3660
3661         var aTypedArray$d = arrayBufferViewCore.aTypedArray;
3662         var exportTypedArrayMethod$e = arrayBufferViewCore.exportTypedArrayMethod;
3663
3664         // `%TypedArray%.prototype.indexOf` method
3665         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.indexof
3666         exportTypedArrayMethod$e('indexOf', function indexOf(searchElement /* , fromIndex */) {
3667           return $indexOf(aTypedArray$d(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
3668         });
3669
3670         var ITERATOR$2 = wellKnownSymbol('iterator');
3671         var Uint8Array$2 = global$2.Uint8Array;
3672         var arrayValues = es_array_iterator.values;
3673         var arrayKeys = es_array_iterator.keys;
3674         var arrayEntries = es_array_iterator.entries;
3675         var aTypedArray$c = arrayBufferViewCore.aTypedArray;
3676         var exportTypedArrayMethod$d = arrayBufferViewCore.exportTypedArrayMethod;
3677         var nativeTypedArrayIterator = Uint8Array$2 && Uint8Array$2.prototype[ITERATOR$2];
3678
3679         var CORRECT_ITER_NAME = !!nativeTypedArrayIterator
3680           && (nativeTypedArrayIterator.name == 'values' || nativeTypedArrayIterator.name == undefined);
3681
3682         var typedArrayValues = function values() {
3683           return arrayValues.call(aTypedArray$c(this));
3684         };
3685
3686         // `%TypedArray%.prototype.entries` method
3687         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.entries
3688         exportTypedArrayMethod$d('entries', function entries() {
3689           return arrayEntries.call(aTypedArray$c(this));
3690         });
3691         // `%TypedArray%.prototype.keys` method
3692         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.keys
3693         exportTypedArrayMethod$d('keys', function keys() {
3694           return arrayKeys.call(aTypedArray$c(this));
3695         });
3696         // `%TypedArray%.prototype.values` method
3697         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.values
3698         exportTypedArrayMethod$d('values', typedArrayValues, !CORRECT_ITER_NAME);
3699         // `%TypedArray%.prototype[@@iterator]` method
3700         // https://tc39.es/ecma262/#sec-%typedarray%.prototype-@@iterator
3701         exportTypedArrayMethod$d(ITERATOR$2, typedArrayValues, !CORRECT_ITER_NAME);
3702
3703         var aTypedArray$b = arrayBufferViewCore.aTypedArray;
3704         var exportTypedArrayMethod$c = arrayBufferViewCore.exportTypedArrayMethod;
3705         var $join = [].join;
3706
3707         // `%TypedArray%.prototype.join` method
3708         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.join
3709         // eslint-disable-next-line no-unused-vars -- required for `.length`
3710         exportTypedArrayMethod$c('join', function join(separator) {
3711           return $join.apply(aTypedArray$b(this), arguments);
3712         });
3713
3714         /* eslint-disable es/no-array-prototype-lastindexof -- safe */
3715
3716
3717
3718
3719
3720         var min$6 = Math.min;
3721         var $lastIndexOf = [].lastIndexOf;
3722         var NEGATIVE_ZERO = !!$lastIndexOf && 1 / [1].lastIndexOf(1, -0) < 0;
3723         var STRICT_METHOD$5 = arrayMethodIsStrict('lastIndexOf');
3724         var FORCED$e = NEGATIVE_ZERO || !STRICT_METHOD$5;
3725
3726         // `Array.prototype.lastIndexOf` method implementation
3727         // https://tc39.es/ecma262/#sec-array.prototype.lastindexof
3728         var arrayLastIndexOf = FORCED$e ? function lastIndexOf(searchElement /* , fromIndex = @[*-1] */) {
3729           // convert -0 to +0
3730           if (NEGATIVE_ZERO) return $lastIndexOf.apply(this, arguments) || 0;
3731           var O = toIndexedObject(this);
3732           var length = toLength(O.length);
3733           var index = length - 1;
3734           if (arguments.length > 1) index = min$6(index, toInteger(arguments[1]));
3735           if (index < 0) index = length + index;
3736           for (;index >= 0; index--) if (index in O && O[index] === searchElement) return index || 0;
3737           return -1;
3738         } : $lastIndexOf;
3739
3740         var aTypedArray$a = arrayBufferViewCore.aTypedArray;
3741         var exportTypedArrayMethod$b = arrayBufferViewCore.exportTypedArrayMethod;
3742
3743         // `%TypedArray%.prototype.lastIndexOf` method
3744         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.lastindexof
3745         // eslint-disable-next-line no-unused-vars -- required for `.length`
3746         exportTypedArrayMethod$b('lastIndexOf', function lastIndexOf(searchElement /* , fromIndex */) {
3747           return arrayLastIndexOf.apply(aTypedArray$a(this), arguments);
3748         });
3749
3750         var $map = arrayIteration.map;
3751
3752
3753         var aTypedArray$9 = arrayBufferViewCore.aTypedArray;
3754         var aTypedArrayConstructor$1 = arrayBufferViewCore.aTypedArrayConstructor;
3755         var exportTypedArrayMethod$a = arrayBufferViewCore.exportTypedArrayMethod;
3756
3757         // `%TypedArray%.prototype.map` method
3758         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.map
3759         exportTypedArrayMethod$a('map', function map(mapfn /* , thisArg */) {
3760           return $map(aTypedArray$9(this), mapfn, arguments.length > 1 ? arguments[1] : undefined, function (O, length) {
3761             return new (aTypedArrayConstructor$1(speciesConstructor(O, O.constructor)))(length);
3762           });
3763         });
3764
3765         // `Array.prototype.{ reduce, reduceRight }` methods implementation
3766         var createMethod$3 = function (IS_RIGHT) {
3767           return function (that, callbackfn, argumentsLength, memo) {
3768             aFunction(callbackfn);
3769             var O = toObject(that);
3770             var self = indexedObject(O);
3771             var length = toLength(O.length);
3772             var index = IS_RIGHT ? length - 1 : 0;
3773             var i = IS_RIGHT ? -1 : 1;
3774             if (argumentsLength < 2) while (true) {
3775               if (index in self) {
3776                 memo = self[index];
3777                 index += i;
3778                 break;
3779               }
3780               index += i;
3781               if (IS_RIGHT ? index < 0 : length <= index) {
3782                 throw TypeError('Reduce of empty array with no initial value');
3783               }
3784             }
3785             for (;IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
3786               memo = callbackfn(memo, self[index], index, O);
3787             }
3788             return memo;
3789           };
3790         };
3791
3792         var arrayReduce = {
3793           // `Array.prototype.reduce` method
3794           // https://tc39.es/ecma262/#sec-array.prototype.reduce
3795           left: createMethod$3(false),
3796           // `Array.prototype.reduceRight` method
3797           // https://tc39.es/ecma262/#sec-array.prototype.reduceright
3798           right: createMethod$3(true)
3799         };
3800
3801         var $reduce$1 = arrayReduce.left;
3802
3803         var aTypedArray$8 = arrayBufferViewCore.aTypedArray;
3804         var exportTypedArrayMethod$9 = arrayBufferViewCore.exportTypedArrayMethod;
3805
3806         // `%TypedArray%.prototype.reduce` method
3807         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduce
3808         exportTypedArrayMethod$9('reduce', function reduce(callbackfn /* , initialValue */) {
3809           return $reduce$1(aTypedArray$8(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
3810         });
3811
3812         var $reduceRight = arrayReduce.right;
3813
3814         var aTypedArray$7 = arrayBufferViewCore.aTypedArray;
3815         var exportTypedArrayMethod$8 = arrayBufferViewCore.exportTypedArrayMethod;
3816
3817         // `%TypedArray%.prototype.reduceRicht` method
3818         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduceright
3819         exportTypedArrayMethod$8('reduceRight', function reduceRight(callbackfn /* , initialValue */) {
3820           return $reduceRight(aTypedArray$7(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
3821         });
3822
3823         var aTypedArray$6 = arrayBufferViewCore.aTypedArray;
3824         var exportTypedArrayMethod$7 = arrayBufferViewCore.exportTypedArrayMethod;
3825         var floor$5 = Math.floor;
3826
3827         // `%TypedArray%.prototype.reverse` method
3828         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reverse
3829         exportTypedArrayMethod$7('reverse', function reverse() {
3830           var that = this;
3831           var length = aTypedArray$6(that).length;
3832           var middle = floor$5(length / 2);
3833           var index = 0;
3834           var value;
3835           while (index < middle) {
3836             value = that[index];
3837             that[index++] = that[--length];
3838             that[length] = value;
3839           } return that;
3840         });
3841
3842         var aTypedArray$5 = arrayBufferViewCore.aTypedArray;
3843         var exportTypedArrayMethod$6 = arrayBufferViewCore.exportTypedArrayMethod;
3844
3845         var FORCED$d = fails(function () {
3846           // eslint-disable-next-line es/no-typed-arrays -- required for testing
3847           new Int8Array(1).set({});
3848         });
3849
3850         // `%TypedArray%.prototype.set` method
3851         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.set
3852         exportTypedArrayMethod$6('set', function set(arrayLike /* , offset */) {
3853           aTypedArray$5(this);
3854           var offset = toOffset(arguments.length > 1 ? arguments[1] : undefined, 1);
3855           var length = this.length;
3856           var src = toObject(arrayLike);
3857           var len = toLength(src.length);
3858           var index = 0;
3859           if (len + offset > length) throw RangeError('Wrong length');
3860           while (index < len) this[offset + index] = src[index++];
3861         }, FORCED$d);
3862
3863         var aTypedArray$4 = arrayBufferViewCore.aTypedArray;
3864         var aTypedArrayConstructor = arrayBufferViewCore.aTypedArrayConstructor;
3865         var exportTypedArrayMethod$5 = arrayBufferViewCore.exportTypedArrayMethod;
3866         var $slice$1 = [].slice;
3867
3868         var FORCED$c = fails(function () {
3869           // eslint-disable-next-line es/no-typed-arrays -- required for testing
3870           new Int8Array(1).slice();
3871         });
3872
3873         // `%TypedArray%.prototype.slice` method
3874         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.slice
3875         exportTypedArrayMethod$5('slice', function slice(start, end) {
3876           var list = $slice$1.call(aTypedArray$4(this), start, end);
3877           var C = speciesConstructor(this, this.constructor);
3878           var index = 0;
3879           var length = list.length;
3880           var result = new (aTypedArrayConstructor(C))(length);
3881           while (length > index) result[index] = list[index++];
3882           return result;
3883         }, FORCED$c);
3884
3885         var $some$1 = arrayIteration.some;
3886
3887         var aTypedArray$3 = arrayBufferViewCore.aTypedArray;
3888         var exportTypedArrayMethod$4 = arrayBufferViewCore.exportTypedArrayMethod;
3889
3890         // `%TypedArray%.prototype.some` method
3891         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.some
3892         exportTypedArrayMethod$4('some', function some(callbackfn /* , thisArg */) {
3893           return $some$1(aTypedArray$3(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3894         });
3895
3896         // TODO: use something more complex like timsort?
3897         var floor$4 = Math.floor;
3898
3899         var mergeSort = function (array, comparefn) {
3900           var length = array.length;
3901           var middle = floor$4(length / 2);
3902           return length < 8 ? insertionSort(array, comparefn) : merge$5(
3903             mergeSort(array.slice(0, middle), comparefn),
3904             mergeSort(array.slice(middle), comparefn),
3905             comparefn
3906           );
3907         };
3908
3909         var insertionSort = function (array, comparefn) {
3910           var length = array.length;
3911           var i = 1;
3912           var element, j;
3913
3914           while (i < length) {
3915             j = i;
3916             element = array[i];
3917             while (j && comparefn(array[j - 1], element) > 0) {
3918               array[j] = array[--j];
3919             }
3920             if (j !== i++) array[j] = element;
3921           } return array;
3922         };
3923
3924         var merge$5 = function (left, right, comparefn) {
3925           var llength = left.length;
3926           var rlength = right.length;
3927           var lindex = 0;
3928           var rindex = 0;
3929           var result = [];
3930
3931           while (lindex < llength || rindex < rlength) {
3932             if (lindex < llength && rindex < rlength) {
3933               result.push(comparefn(left[lindex], right[rindex]) <= 0 ? left[lindex++] : right[rindex++]);
3934             } else {
3935               result.push(lindex < llength ? left[lindex++] : right[rindex++]);
3936             }
3937           } return result;
3938         };
3939
3940         var arraySort = mergeSort;
3941
3942         var firefox = engineUserAgent.match(/firefox\/(\d+)/i);
3943
3944         var engineFfVersion = !!firefox && +firefox[1];
3945
3946         var engineIsIeOrEdge = /MSIE|Trident/.test(engineUserAgent);
3947
3948         var webkit = engineUserAgent.match(/AppleWebKit\/(\d+)\./);
3949
3950         var engineWebkitVersion = !!webkit && +webkit[1];
3951
3952         var aTypedArray$2 = arrayBufferViewCore.aTypedArray;
3953         var exportTypedArrayMethod$3 = arrayBufferViewCore.exportTypedArrayMethod;
3954         var Uint16Array = global$2.Uint16Array;
3955         var nativeSort$1 = Uint16Array && Uint16Array.prototype.sort;
3956
3957         // WebKit
3958         var ACCEPT_INCORRECT_ARGUMENTS = !!nativeSort$1 && !fails(function () {
3959           var array = new Uint16Array(2);
3960           array.sort(null);
3961           array.sort({});
3962         });
3963
3964         var STABLE_SORT$1 = !!nativeSort$1 && !fails(function () {
3965           // feature detection can be too slow, so check engines versions
3966           if (engineV8Version) return engineV8Version < 74;
3967           if (engineFfVersion) return engineFfVersion < 67;
3968           if (engineIsIeOrEdge) return true;
3969           if (engineWebkitVersion) return engineWebkitVersion < 602;
3970
3971           var array = new Uint16Array(516);
3972           var expected = Array(516);
3973           var index, mod;
3974
3975           for (index = 0; index < 516; index++) {
3976             mod = index % 4;
3977             array[index] = 515 - index;
3978             expected[index] = index - 2 * mod + 3;
3979           }
3980
3981           array.sort(function (a, b) {
3982             return (a / 4 | 0) - (b / 4 | 0);
3983           });
3984
3985           for (index = 0; index < 516; index++) {
3986             if (array[index] !== expected[index]) return true;
3987           }
3988         });
3989
3990         var getSortCompare$1 = function (comparefn) {
3991           return function (x, y) {
3992             if (comparefn !== undefined) return +comparefn(x, y) || 0;
3993             // eslint-disable-next-line no-self-compare -- NaN check
3994             if (y !== y) return -1;
3995             // eslint-disable-next-line no-self-compare -- NaN check
3996             if (x !== x) return 1;
3997             if (x === 0 && y === 0) return 1 / x > 0 && 1 / y < 0 ? 1 : -1;
3998             return x > y;
3999           };
4000         };
4001
4002         // `%TypedArray%.prototype.sort` method
4003         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.sort
4004         exportTypedArrayMethod$3('sort', function sort(comparefn) {
4005           var array = this;
4006           if (comparefn !== undefined) aFunction(comparefn);
4007           if (STABLE_SORT$1) return nativeSort$1.call(array, comparefn);
4008
4009           aTypedArray$2(array);
4010           var arrayLength = toLength(array.length);
4011           var items = Array(arrayLength);
4012           var index;
4013
4014           for (index = 0; index < arrayLength; index++) {
4015             items[index] = array[index];
4016           }
4017
4018           items = arraySort(array, getSortCompare$1(comparefn));
4019
4020           for (index = 0; index < arrayLength; index++) {
4021             array[index] = items[index];
4022           }
4023
4024           return array;
4025         }, !STABLE_SORT$1 || ACCEPT_INCORRECT_ARGUMENTS);
4026
4027         var aTypedArray$1 = arrayBufferViewCore.aTypedArray;
4028         var exportTypedArrayMethod$2 = arrayBufferViewCore.exportTypedArrayMethod;
4029
4030         // `%TypedArray%.prototype.subarray` method
4031         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.subarray
4032         exportTypedArrayMethod$2('subarray', function subarray(begin, end) {
4033           var O = aTypedArray$1(this);
4034           var length = O.length;
4035           var beginIndex = toAbsoluteIndex(begin, length);
4036           return new (speciesConstructor(O, O.constructor))(
4037             O.buffer,
4038             O.byteOffset + beginIndex * O.BYTES_PER_ELEMENT,
4039             toLength((end === undefined ? length : toAbsoluteIndex(end, length)) - beginIndex)
4040           );
4041         });
4042
4043         var Int8Array$1 = global$2.Int8Array;
4044         var aTypedArray = arrayBufferViewCore.aTypedArray;
4045         var exportTypedArrayMethod$1 = arrayBufferViewCore.exportTypedArrayMethod;
4046         var $toLocaleString = [].toLocaleString;
4047         var $slice = [].slice;
4048
4049         // iOS Safari 6.x fails here
4050         var TO_LOCALE_STRING_BUG = !!Int8Array$1 && fails(function () {
4051           $toLocaleString.call(new Int8Array$1(1));
4052         });
4053
4054         var FORCED$b = fails(function () {
4055           return [1, 2].toLocaleString() != new Int8Array$1([1, 2]).toLocaleString();
4056         }) || !fails(function () {
4057           Int8Array$1.prototype.toLocaleString.call([1, 2]);
4058         });
4059
4060         // `%TypedArray%.prototype.toLocaleString` method
4061         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.tolocalestring
4062         exportTypedArrayMethod$1('toLocaleString', function toLocaleString() {
4063           return $toLocaleString.apply(TO_LOCALE_STRING_BUG ? $slice.call(aTypedArray(this)) : aTypedArray(this), arguments);
4064         }, FORCED$b);
4065
4066         var exportTypedArrayMethod = arrayBufferViewCore.exportTypedArrayMethod;
4067
4068
4069
4070         var Uint8Array$1 = global$2.Uint8Array;
4071         var Uint8ArrayPrototype = Uint8Array$1 && Uint8Array$1.prototype || {};
4072         var arrayToString = [].toString;
4073         var arrayJoin = [].join;
4074
4075         if (fails(function () { arrayToString.call({}); })) {
4076           arrayToString = function toString() {
4077             return arrayJoin.call(this);
4078           };
4079         }
4080
4081         var IS_NOT_ARRAY_METHOD = Uint8ArrayPrototype.toString != arrayToString;
4082
4083         // `%TypedArray%.prototype.toString` method
4084         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.tostring
4085         exportTypedArrayMethod('toString', arrayToString, IS_NOT_ARRAY_METHOD);
4086
4087         var nativeJoin = [].join;
4088
4089         var ES3_STRINGS = indexedObject != Object;
4090         var STRICT_METHOD$4 = arrayMethodIsStrict('join', ',');
4091
4092         // `Array.prototype.join` method
4093         // https://tc39.es/ecma262/#sec-array.prototype.join
4094         _export({ target: 'Array', proto: true, forced: ES3_STRINGS || !STRICT_METHOD$4 }, {
4095           join: function join(separator) {
4096             return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
4097           }
4098         });
4099
4100         var createProperty = function (object, key, value) {
4101           var propertyKey = toPrimitive(key);
4102           if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));
4103           else object[propertyKey] = value;
4104         };
4105
4106         var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport('slice');
4107
4108         var SPECIES$1 = wellKnownSymbol('species');
4109         var nativeSlice = [].slice;
4110         var max$3 = Math.max;
4111
4112         // `Array.prototype.slice` method
4113         // https://tc39.es/ecma262/#sec-array.prototype.slice
4114         // fallback for not array-like ES3 strings and DOM objects
4115         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$2 }, {
4116           slice: function slice(start, end) {
4117             var O = toIndexedObject(this);
4118             var length = toLength(O.length);
4119             var k = toAbsoluteIndex(start, length);
4120             var fin = toAbsoluteIndex(end === undefined ? length : end, length);
4121             // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
4122             var Constructor, result, n;
4123             if (isArray(O)) {
4124               Constructor = O.constructor;
4125               // cross-realm fallback
4126               if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) {
4127                 Constructor = undefined;
4128               } else if (isObject$4(Constructor)) {
4129                 Constructor = Constructor[SPECIES$1];
4130                 if (Constructor === null) Constructor = undefined;
4131               }
4132               if (Constructor === Array || Constructor === undefined) {
4133                 return nativeSlice.call(O, k, fin);
4134               }
4135             }
4136             result = new (Constructor === undefined ? Array : Constructor)(max$3(fin - k, 0));
4137             for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);
4138             result.length = n;
4139             return result;
4140           }
4141         });
4142
4143         var ITERATOR$1 = wellKnownSymbol('iterator');
4144
4145         var nativeUrl = !fails(function () {
4146           var url = new URL('b?a=1&b=2&c=3', 'http://a');
4147           var searchParams = url.searchParams;
4148           var result = '';
4149           url.pathname = 'c%20d';
4150           searchParams.forEach(function (value, key) {
4151             searchParams['delete']('b');
4152             result += key + value;
4153           });
4154           return (isPure && !url.toJSON)
4155             || !searchParams.sort
4156             || url.href !== 'http://a/c%20d?a=1&c=3'
4157             || searchParams.get('c') !== '3'
4158             || String(new URLSearchParams('?a=1')) !== 'a=1'
4159             || !searchParams[ITERATOR$1]
4160             // throws in Edge
4161             || new URL('https://a@b').username !== 'a'
4162             || new URLSearchParams(new URLSearchParams('a=b')).get('a') !== 'b'
4163             // not punycoded in Edge
4164             || new URL('http://тест').host !== 'xn--e1aybc'
4165             // not escaped in Chrome 62-
4166             || new URL('http://a#б').hash !== '#%D0%B1'
4167             // fails in Chrome 66-
4168             || result !== 'a1c3'
4169             // throws in Safari
4170             || new URL('http://x', undefined).host !== 'x';
4171         });
4172
4173         // eslint-disable-next-line es/no-object-assign -- safe
4174         var $assign = Object.assign;
4175         // eslint-disable-next-line es/no-object-defineproperty -- required for testing
4176         var defineProperty$4 = Object.defineProperty;
4177
4178         // `Object.assign` method
4179         // https://tc39.es/ecma262/#sec-object.assign
4180         var objectAssign = !$assign || fails(function () {
4181           // should have correct order of operations (Edge bug)
4182           if (descriptors && $assign({ b: 1 }, $assign(defineProperty$4({}, 'a', {
4183             enumerable: true,
4184             get: function () {
4185               defineProperty$4(this, 'b', {
4186                 value: 3,
4187                 enumerable: false
4188               });
4189             }
4190           }), { b: 2 })).b !== 1) return true;
4191           // should work with symbols and should have deterministic property order (V8 bug)
4192           var A = {};
4193           var B = {};
4194           // eslint-disable-next-line es/no-symbol -- safe
4195           var symbol = Symbol();
4196           var alphabet = 'abcdefghijklmnopqrst';
4197           A[symbol] = 7;
4198           alphabet.split('').forEach(function (chr) { B[chr] = chr; });
4199           return $assign({}, A)[symbol] != 7 || objectKeys($assign({}, B)).join('') != alphabet;
4200         }) ? function assign(target, source) { // eslint-disable-line no-unused-vars -- required for `.length`
4201           var T = toObject(target);
4202           var argumentsLength = arguments.length;
4203           var index = 1;
4204           var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
4205           var propertyIsEnumerable = objectPropertyIsEnumerable.f;
4206           while (argumentsLength > index) {
4207             var S = indexedObject(arguments[index++]);
4208             var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
4209             var length = keys.length;
4210             var j = 0;
4211             var key;
4212             while (length > j) {
4213               key = keys[j++];
4214               if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
4215             }
4216           } return T;
4217         } : $assign;
4218
4219         // call something on iterator step with safe closing on error
4220         var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
4221           try {
4222             return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
4223           } catch (error) {
4224             iteratorClose(iterator);
4225             throw error;
4226           }
4227         };
4228
4229         // `Array.from` method implementation
4230         // https://tc39.es/ecma262/#sec-array.from
4231         var arrayFrom = function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {
4232           var O = toObject(arrayLike);
4233           var C = typeof this == 'function' ? this : Array;
4234           var argumentsLength = arguments.length;
4235           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
4236           var mapping = mapfn !== undefined;
4237           var iteratorMethod = getIteratorMethod(O);
4238           var index = 0;
4239           var length, result, step, iterator, next, value;
4240           if (mapping) mapfn = functionBindContext(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2);
4241           // if the target is not iterable or it's an array with the default iterator - use a simple case
4242           if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod(iteratorMethod))) {
4243             iterator = iteratorMethod.call(O);
4244             next = iterator.next;
4245             result = new C();
4246             for (;!(step = next.call(iterator)).done; index++) {
4247               value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
4248               createProperty(result, index, value);
4249             }
4250           } else {
4251             length = toLength(O.length);
4252             result = new C(length);
4253             for (;length > index; index++) {
4254               value = mapping ? mapfn(O[index], index) : O[index];
4255               createProperty(result, index, value);
4256             }
4257           }
4258           result.length = index;
4259           return result;
4260         };
4261
4262         // based on https://github.com/bestiejs/punycode.js/blob/master/punycode.js
4263         var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
4264         var base = 36;
4265         var tMin = 1;
4266         var tMax = 26;
4267         var skew = 38;
4268         var damp = 700;
4269         var initialBias = 72;
4270         var initialN = 128; // 0x80
4271         var delimiter = '-'; // '\x2D'
4272         var regexNonASCII = /[^\0-\u007E]/; // non-ASCII chars
4273         var regexSeparators = /[.\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
4274         var OVERFLOW_ERROR = 'Overflow: input needs wider integers to process';
4275         var baseMinusTMin = base - tMin;
4276         var floor$3 = Math.floor;
4277         var stringFromCharCode = String.fromCharCode;
4278
4279         /**
4280          * Creates an array containing the numeric code points of each Unicode
4281          * character in the string. While JavaScript uses UCS-2 internally,
4282          * this function will convert a pair of surrogate halves (each of which
4283          * UCS-2 exposes as separate characters) into a single code point,
4284          * matching UTF-16.
4285          */
4286         var ucs2decode = function (string) {
4287           var output = [];
4288           var counter = 0;
4289           var length = string.length;
4290           while (counter < length) {
4291             var value = string.charCodeAt(counter++);
4292             if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
4293               // It's a high surrogate, and there is a next character.
4294               var extra = string.charCodeAt(counter++);
4295               if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
4296                 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
4297               } else {
4298                 // It's an unmatched surrogate; only append this code unit, in case the
4299                 // next code unit is the high surrogate of a surrogate pair.
4300                 output.push(value);
4301                 counter--;
4302               }
4303             } else {
4304               output.push(value);
4305             }
4306           }
4307           return output;
4308         };
4309
4310         /**
4311          * Converts a digit/integer into a basic code point.
4312          */
4313         var digitToBasic = function (digit) {
4314           //  0..25 map to ASCII a..z or A..Z
4315           // 26..35 map to ASCII 0..9
4316           return digit + 22 + 75 * (digit < 26);
4317         };
4318
4319         /**
4320          * Bias adaptation function as per section 3.4 of RFC 3492.
4321          * https://tools.ietf.org/html/rfc3492#section-3.4
4322          */
4323         var adapt = function (delta, numPoints, firstTime) {
4324           var k = 0;
4325           delta = firstTime ? floor$3(delta / damp) : delta >> 1;
4326           delta += floor$3(delta / numPoints);
4327           for (; delta > baseMinusTMin * tMax >> 1; k += base) {
4328             delta = floor$3(delta / baseMinusTMin);
4329           }
4330           return floor$3(k + (baseMinusTMin + 1) * delta / (delta + skew));
4331         };
4332
4333         /**
4334          * Converts a string of Unicode symbols (e.g. a domain name label) to a
4335          * Punycode string of ASCII-only symbols.
4336          */
4337         // eslint-disable-next-line max-statements -- TODO
4338         var encode = function (input) {
4339           var output = [];
4340
4341           // Convert the input in UCS-2 to an array of Unicode code points.
4342           input = ucs2decode(input);
4343
4344           // Cache the length.
4345           var inputLength = input.length;
4346
4347           // Initialize the state.
4348           var n = initialN;
4349           var delta = 0;
4350           var bias = initialBias;
4351           var i, currentValue;
4352
4353           // Handle the basic code points.
4354           for (i = 0; i < input.length; i++) {
4355             currentValue = input[i];
4356             if (currentValue < 0x80) {
4357               output.push(stringFromCharCode(currentValue));
4358             }
4359           }
4360
4361           var basicLength = output.length; // number of basic code points.
4362           var handledCPCount = basicLength; // number of code points that have been handled;
4363
4364           // Finish the basic string with a delimiter unless it's empty.
4365           if (basicLength) {
4366             output.push(delimiter);
4367           }
4368
4369           // Main encoding loop:
4370           while (handledCPCount < inputLength) {
4371             // All non-basic code points < n have been handled already. Find the next larger one:
4372             var m = maxInt;
4373             for (i = 0; i < input.length; i++) {
4374               currentValue = input[i];
4375               if (currentValue >= n && currentValue < m) {
4376                 m = currentValue;
4377               }
4378             }
4379
4380             // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, but guard against overflow.
4381             var handledCPCountPlusOne = handledCPCount + 1;
4382             if (m - n > floor$3((maxInt - delta) / handledCPCountPlusOne)) {
4383               throw RangeError(OVERFLOW_ERROR);
4384             }
4385
4386             delta += (m - n) * handledCPCountPlusOne;
4387             n = m;
4388
4389             for (i = 0; i < input.length; i++) {
4390               currentValue = input[i];
4391               if (currentValue < n && ++delta > maxInt) {
4392                 throw RangeError(OVERFLOW_ERROR);
4393               }
4394               if (currentValue == n) {
4395                 // Represent delta as a generalized variable-length integer.
4396                 var q = delta;
4397                 for (var k = base; /* no condition */; k += base) {
4398                   var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
4399                   if (q < t) break;
4400                   var qMinusT = q - t;
4401                   var baseMinusT = base - t;
4402                   output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT)));
4403                   q = floor$3(qMinusT / baseMinusT);
4404                 }
4405
4406                 output.push(stringFromCharCode(digitToBasic(q)));
4407                 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
4408                 delta = 0;
4409                 ++handledCPCount;
4410               }
4411             }
4412
4413             ++delta;
4414             ++n;
4415           }
4416           return output.join('');
4417         };
4418
4419         var stringPunycodeToAscii = function (input) {
4420           var encoded = [];
4421           var labels = input.toLowerCase().replace(regexSeparators, '\u002E').split('.');
4422           var i, label;
4423           for (i = 0; i < labels.length; i++) {
4424             label = labels[i];
4425             encoded.push(regexNonASCII.test(label) ? 'xn--' + encode(label) : label);
4426           }
4427           return encoded.join('.');
4428         };
4429
4430         var getIterator = function (it) {
4431           var iteratorMethod = getIteratorMethod(it);
4432           if (typeof iteratorMethod != 'function') {
4433             throw TypeError(String(it) + ' is not iterable');
4434           } return anObject(iteratorMethod.call(it));
4435         };
4436
4437         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459         var $fetch = getBuiltIn('fetch');
4460         var Headers$1 = getBuiltIn('Headers');
4461         var ITERATOR = wellKnownSymbol('iterator');
4462         var URL_SEARCH_PARAMS = 'URLSearchParams';
4463         var URL_SEARCH_PARAMS_ITERATOR = URL_SEARCH_PARAMS + 'Iterator';
4464         var setInternalState$2 = internalState.set;
4465         var getInternalParamsState = internalState.getterFor(URL_SEARCH_PARAMS);
4466         var getInternalIteratorState = internalState.getterFor(URL_SEARCH_PARAMS_ITERATOR);
4467
4468         var plus = /\+/g;
4469         var sequences = Array(4);
4470
4471         var percentSequence = function (bytes) {
4472           return sequences[bytes - 1] || (sequences[bytes - 1] = RegExp('((?:%[\\da-f]{2}){' + bytes + '})', 'gi'));
4473         };
4474
4475         var percentDecode = function (sequence) {
4476           try {
4477             return decodeURIComponent(sequence);
4478           } catch (error) {
4479             return sequence;
4480           }
4481         };
4482
4483         var deserialize = function (it) {
4484           var result = it.replace(plus, ' ');
4485           var bytes = 4;
4486           try {
4487             return decodeURIComponent(result);
4488           } catch (error) {
4489             while (bytes) {
4490               result = result.replace(percentSequence(bytes--), percentDecode);
4491             }
4492             return result;
4493           }
4494         };
4495
4496         var find$1 = /[!'()~]|%20/g;
4497
4498         var replace$1 = {
4499           '!': '%21',
4500           "'": '%27',
4501           '(': '%28',
4502           ')': '%29',
4503           '~': '%7E',
4504           '%20': '+'
4505         };
4506
4507         var replacer = function (match) {
4508           return replace$1[match];
4509         };
4510
4511         var serialize = function (it) {
4512           return encodeURIComponent(it).replace(find$1, replacer);
4513         };
4514
4515         var parseSearchParams = function (result, query) {
4516           if (query) {
4517             var attributes = query.split('&');
4518             var index = 0;
4519             var attribute, entry;
4520             while (index < attributes.length) {
4521               attribute = attributes[index++];
4522               if (attribute.length) {
4523                 entry = attribute.split('=');
4524                 result.push({
4525                   key: deserialize(entry.shift()),
4526                   value: deserialize(entry.join('='))
4527                 });
4528               }
4529             }
4530           }
4531         };
4532
4533         var updateSearchParams = function (query) {
4534           this.entries.length = 0;
4535           parseSearchParams(this.entries, query);
4536         };
4537
4538         var validateArgumentsLength = function (passed, required) {
4539           if (passed < required) throw TypeError('Not enough arguments');
4540         };
4541
4542         var URLSearchParamsIterator = createIteratorConstructor(function Iterator(params, kind) {
4543           setInternalState$2(this, {
4544             type: URL_SEARCH_PARAMS_ITERATOR,
4545             iterator: getIterator(getInternalParamsState(params).entries),
4546             kind: kind
4547           });
4548         }, 'Iterator', function next() {
4549           var state = getInternalIteratorState(this);
4550           var kind = state.kind;
4551           var step = state.iterator.next();
4552           var entry = step.value;
4553           if (!step.done) {
4554             step.value = kind === 'keys' ? entry.key : kind === 'values' ? entry.value : [entry.key, entry.value];
4555           } return step;
4556         });
4557
4558         // `URLSearchParams` constructor
4559         // https://url.spec.whatwg.org/#interface-urlsearchparams
4560         var URLSearchParamsConstructor = function URLSearchParams(/* init */) {
4561           anInstance(this, URLSearchParamsConstructor, URL_SEARCH_PARAMS);
4562           var init = arguments.length > 0 ? arguments[0] : undefined;
4563           var that = this;
4564           var entries = [];
4565           var iteratorMethod, iterator, next, step, entryIterator, entryNext, first, second, key;
4566
4567           setInternalState$2(that, {
4568             type: URL_SEARCH_PARAMS,
4569             entries: entries,
4570             updateURL: function () { /* empty */ },
4571             updateSearchParams: updateSearchParams
4572           });
4573
4574           if (init !== undefined) {
4575             if (isObject$4(init)) {
4576               iteratorMethod = getIteratorMethod(init);
4577               if (typeof iteratorMethod === 'function') {
4578                 iterator = iteratorMethod.call(init);
4579                 next = iterator.next;
4580                 while (!(step = next.call(iterator)).done) {
4581                   entryIterator = getIterator(anObject(step.value));
4582                   entryNext = entryIterator.next;
4583                   if (
4584                     (first = entryNext.call(entryIterator)).done ||
4585                     (second = entryNext.call(entryIterator)).done ||
4586                     !entryNext.call(entryIterator).done
4587                   ) throw TypeError('Expected sequence with length 2');
4588                   entries.push({ key: first.value + '', value: second.value + '' });
4589                 }
4590               } else for (key in init) if (has$1(init, key)) entries.push({ key: key, value: init[key] + '' });
4591             } else {
4592               parseSearchParams(entries, typeof init === 'string' ? init.charAt(0) === '?' ? init.slice(1) : init : init + '');
4593             }
4594           }
4595         };
4596
4597         var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
4598
4599         redefineAll(URLSearchParamsPrototype, {
4600           // `URLSearchParams.prototype.append` method
4601           // https://url.spec.whatwg.org/#dom-urlsearchparams-append
4602           append: function append(name, value) {
4603             validateArgumentsLength(arguments.length, 2);
4604             var state = getInternalParamsState(this);
4605             state.entries.push({ key: name + '', value: value + '' });
4606             state.updateURL();
4607           },
4608           // `URLSearchParams.prototype.delete` method
4609           // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
4610           'delete': function (name) {
4611             validateArgumentsLength(arguments.length, 1);
4612             var state = getInternalParamsState(this);
4613             var entries = state.entries;
4614             var key = name + '';
4615             var index = 0;
4616             while (index < entries.length) {
4617               if (entries[index].key === key) entries.splice(index, 1);
4618               else index++;
4619             }
4620             state.updateURL();
4621           },
4622           // `URLSearchParams.prototype.get` method
4623           // https://url.spec.whatwg.org/#dom-urlsearchparams-get
4624           get: function get(name) {
4625             validateArgumentsLength(arguments.length, 1);
4626             var entries = getInternalParamsState(this).entries;
4627             var key = name + '';
4628             var index = 0;
4629             for (; index < entries.length; index++) {
4630               if (entries[index].key === key) return entries[index].value;
4631             }
4632             return null;
4633           },
4634           // `URLSearchParams.prototype.getAll` method
4635           // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
4636           getAll: function getAll(name) {
4637             validateArgumentsLength(arguments.length, 1);
4638             var entries = getInternalParamsState(this).entries;
4639             var key = name + '';
4640             var result = [];
4641             var index = 0;
4642             for (; index < entries.length; index++) {
4643               if (entries[index].key === key) result.push(entries[index].value);
4644             }
4645             return result;
4646           },
4647           // `URLSearchParams.prototype.has` method
4648           // https://url.spec.whatwg.org/#dom-urlsearchparams-has
4649           has: function has(name) {
4650             validateArgumentsLength(arguments.length, 1);
4651             var entries = getInternalParamsState(this).entries;
4652             var key = name + '';
4653             var index = 0;
4654             while (index < entries.length) {
4655               if (entries[index++].key === key) return true;
4656             }
4657             return false;
4658           },
4659           // `URLSearchParams.prototype.set` method
4660           // https://url.spec.whatwg.org/#dom-urlsearchparams-set
4661           set: function set(name, value) {
4662             validateArgumentsLength(arguments.length, 1);
4663             var state = getInternalParamsState(this);
4664             var entries = state.entries;
4665             var found = false;
4666             var key = name + '';
4667             var val = value + '';
4668             var index = 0;
4669             var entry;
4670             for (; index < entries.length; index++) {
4671               entry = entries[index];
4672               if (entry.key === key) {
4673                 if (found) entries.splice(index--, 1);
4674                 else {
4675                   found = true;
4676                   entry.value = val;
4677                 }
4678               }
4679             }
4680             if (!found) entries.push({ key: key, value: val });
4681             state.updateURL();
4682           },
4683           // `URLSearchParams.prototype.sort` method
4684           // https://url.spec.whatwg.org/#dom-urlsearchparams-sort
4685           sort: function sort() {
4686             var state = getInternalParamsState(this);
4687             var entries = state.entries;
4688             // Array#sort is not stable in some engines
4689             var slice = entries.slice();
4690             var entry, entriesIndex, sliceIndex;
4691             entries.length = 0;
4692             for (sliceIndex = 0; sliceIndex < slice.length; sliceIndex++) {
4693               entry = slice[sliceIndex];
4694               for (entriesIndex = 0; entriesIndex < sliceIndex; entriesIndex++) {
4695                 if (entries[entriesIndex].key > entry.key) {
4696                   entries.splice(entriesIndex, 0, entry);
4697                   break;
4698                 }
4699               }
4700               if (entriesIndex === sliceIndex) entries.push(entry);
4701             }
4702             state.updateURL();
4703           },
4704           // `URLSearchParams.prototype.forEach` method
4705           forEach: function forEach(callback /* , thisArg */) {
4706             var entries = getInternalParamsState(this).entries;
4707             var boundFunction = functionBindContext(callback, arguments.length > 1 ? arguments[1] : undefined, 3);
4708             var index = 0;
4709             var entry;
4710             while (index < entries.length) {
4711               entry = entries[index++];
4712               boundFunction(entry.value, entry.key, this);
4713             }
4714           },
4715           // `URLSearchParams.prototype.keys` method
4716           keys: function keys() {
4717             return new URLSearchParamsIterator(this, 'keys');
4718           },
4719           // `URLSearchParams.prototype.values` method
4720           values: function values() {
4721             return new URLSearchParamsIterator(this, 'values');
4722           },
4723           // `URLSearchParams.prototype.entries` method
4724           entries: function entries() {
4725             return new URLSearchParamsIterator(this, 'entries');
4726           }
4727         }, { enumerable: true });
4728
4729         // `URLSearchParams.prototype[@@iterator]` method
4730         redefine(URLSearchParamsPrototype, ITERATOR, URLSearchParamsPrototype.entries);
4731
4732         // `URLSearchParams.prototype.toString` method
4733         // https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
4734         redefine(URLSearchParamsPrototype, 'toString', function toString() {
4735           var entries = getInternalParamsState(this).entries;
4736           var result = [];
4737           var index = 0;
4738           var entry;
4739           while (index < entries.length) {
4740             entry = entries[index++];
4741             result.push(serialize(entry.key) + '=' + serialize(entry.value));
4742           } return result.join('&');
4743         }, { enumerable: true });
4744
4745         setToStringTag(URLSearchParamsConstructor, URL_SEARCH_PARAMS);
4746
4747         _export({ global: true, forced: !nativeUrl }, {
4748           URLSearchParams: URLSearchParamsConstructor
4749         });
4750
4751         // Wrap `fetch` for correct work with polyfilled `URLSearchParams`
4752         // https://github.com/zloirock/core-js/issues/674
4753         if (!nativeUrl && typeof $fetch == 'function' && typeof Headers$1 == 'function') {
4754           _export({ global: true, enumerable: true, forced: true }, {
4755             fetch: function fetch(input /* , init */) {
4756               var args = [input];
4757               var init, body, headers;
4758               if (arguments.length > 1) {
4759                 init = arguments[1];
4760                 if (isObject$4(init)) {
4761                   body = init.body;
4762                   if (classof(body) === URL_SEARCH_PARAMS) {
4763                     headers = init.headers ? new Headers$1(init.headers) : new Headers$1();
4764                     if (!headers.has('content-type')) {
4765                       headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
4766                     }
4767                     init = objectCreate(init, {
4768                       body: createPropertyDescriptor(0, String(body)),
4769                       headers: createPropertyDescriptor(0, headers)
4770                     });
4771                   }
4772                 }
4773                 args.push(init);
4774               } return $fetch.apply(this, args);
4775             }
4776           });
4777         }
4778
4779         var web_urlSearchParams = {
4780           URLSearchParams: URLSearchParamsConstructor,
4781           getState: getInternalParamsState
4782         };
4783
4784         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796         var codeAt = stringMultibyte.codeAt;
4797
4798
4799
4800
4801
4802         var NativeURL = global$2.URL;
4803         var URLSearchParams$1 = web_urlSearchParams.URLSearchParams;
4804         var getInternalSearchParamsState = web_urlSearchParams.getState;
4805         var setInternalState$1 = internalState.set;
4806         var getInternalURLState = internalState.getterFor('URL');
4807         var floor$2 = Math.floor;
4808         var pow$1 = Math.pow;
4809
4810         var INVALID_AUTHORITY = 'Invalid authority';
4811         var INVALID_SCHEME = 'Invalid scheme';
4812         var INVALID_HOST = 'Invalid host';
4813         var INVALID_PORT = 'Invalid port';
4814
4815         var ALPHA = /[A-Za-z]/;
4816         // eslint-disable-next-line regexp/no-obscure-range -- safe
4817         var ALPHANUMERIC = /[\d+-.A-Za-z]/;
4818         var DIGIT = /\d/;
4819         var HEX_START = /^0x/i;
4820         var OCT = /^[0-7]+$/;
4821         var DEC = /^\d+$/;
4822         var HEX = /^[\dA-Fa-f]+$/;
4823         /* eslint-disable no-control-regex -- safe */
4824         var FORBIDDEN_HOST_CODE_POINT = /[\0\t\n\r #%/:<>?@[\\\]^|]/;
4825         var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\0\t\n\r #/:<>?@[\\\]^|]/;
4826         var LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE = /^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g;
4827         var TAB_AND_NEW_LINE = /[\t\n\r]/g;
4828         /* eslint-enable no-control-regex -- safe */
4829         var EOF;
4830
4831         var parseHost = function (url, input) {
4832           var result, codePoints, index;
4833           if (input.charAt(0) == '[') {
4834             if (input.charAt(input.length - 1) != ']') return INVALID_HOST;
4835             result = parseIPv6(input.slice(1, -1));
4836             if (!result) return INVALID_HOST;
4837             url.host = result;
4838           // opaque host
4839           } else if (!isSpecial(url)) {
4840             if (FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT.test(input)) return INVALID_HOST;
4841             result = '';
4842             codePoints = arrayFrom(input);
4843             for (index = 0; index < codePoints.length; index++) {
4844               result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
4845             }
4846             url.host = result;
4847           } else {
4848             input = stringPunycodeToAscii(input);
4849             if (FORBIDDEN_HOST_CODE_POINT.test(input)) return INVALID_HOST;
4850             result = parseIPv4(input);
4851             if (result === null) return INVALID_HOST;
4852             url.host = result;
4853           }
4854         };
4855
4856         var parseIPv4 = function (input) {
4857           var parts = input.split('.');
4858           var partsLength, numbers, index, part, radix, number, ipv4;
4859           if (parts.length && parts[parts.length - 1] == '') {
4860             parts.pop();
4861           }
4862           partsLength = parts.length;
4863           if (partsLength > 4) return input;
4864           numbers = [];
4865           for (index = 0; index < partsLength; index++) {
4866             part = parts[index];
4867             if (part == '') return input;
4868             radix = 10;
4869             if (part.length > 1 && part.charAt(0) == '0') {
4870               radix = HEX_START.test(part) ? 16 : 8;
4871               part = part.slice(radix == 8 ? 1 : 2);
4872             }
4873             if (part === '') {
4874               number = 0;
4875             } else {
4876               if (!(radix == 10 ? DEC : radix == 8 ? OCT : HEX).test(part)) return input;
4877               number = parseInt(part, radix);
4878             }
4879             numbers.push(number);
4880           }
4881           for (index = 0; index < partsLength; index++) {
4882             number = numbers[index];
4883             if (index == partsLength - 1) {
4884               if (number >= pow$1(256, 5 - partsLength)) return null;
4885             } else if (number > 255) return null;
4886           }
4887           ipv4 = numbers.pop();
4888           for (index = 0; index < numbers.length; index++) {
4889             ipv4 += numbers[index] * pow$1(256, 3 - index);
4890           }
4891           return ipv4;
4892         };
4893
4894         // eslint-disable-next-line max-statements -- TODO
4895         var parseIPv6 = function (input) {
4896           var address = [0, 0, 0, 0, 0, 0, 0, 0];
4897           var pieceIndex = 0;
4898           var compress = null;
4899           var pointer = 0;
4900           var value, length, numbersSeen, ipv4Piece, number, swaps, swap;
4901
4902           var char = function () {
4903             return input.charAt(pointer);
4904           };
4905
4906           if (char() == ':') {
4907             if (input.charAt(1) != ':') return;
4908             pointer += 2;
4909             pieceIndex++;
4910             compress = pieceIndex;
4911           }
4912           while (char()) {
4913             if (pieceIndex == 8) return;
4914             if (char() == ':') {
4915               if (compress !== null) return;
4916               pointer++;
4917               pieceIndex++;
4918               compress = pieceIndex;
4919               continue;
4920             }
4921             value = length = 0;
4922             while (length < 4 && HEX.test(char())) {
4923               value = value * 16 + parseInt(char(), 16);
4924               pointer++;
4925               length++;
4926             }
4927             if (char() == '.') {
4928               if (length == 0) return;
4929               pointer -= length;
4930               if (pieceIndex > 6) return;
4931               numbersSeen = 0;
4932               while (char()) {
4933                 ipv4Piece = null;
4934                 if (numbersSeen > 0) {
4935                   if (char() == '.' && numbersSeen < 4) pointer++;
4936                   else return;
4937                 }
4938                 if (!DIGIT.test(char())) return;
4939                 while (DIGIT.test(char())) {
4940                   number = parseInt(char(), 10);
4941                   if (ipv4Piece === null) ipv4Piece = number;
4942                   else if (ipv4Piece == 0) return;
4943                   else ipv4Piece = ipv4Piece * 10 + number;
4944                   if (ipv4Piece > 255) return;
4945                   pointer++;
4946                 }
4947                 address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
4948                 numbersSeen++;
4949                 if (numbersSeen == 2 || numbersSeen == 4) pieceIndex++;
4950               }
4951               if (numbersSeen != 4) return;
4952               break;
4953             } else if (char() == ':') {
4954               pointer++;
4955               if (!char()) return;
4956             } else if (char()) return;
4957             address[pieceIndex++] = value;
4958           }
4959           if (compress !== null) {
4960             swaps = pieceIndex - compress;
4961             pieceIndex = 7;
4962             while (pieceIndex != 0 && swaps > 0) {
4963               swap = address[pieceIndex];
4964               address[pieceIndex--] = address[compress + swaps - 1];
4965               address[compress + --swaps] = swap;
4966             }
4967           } else if (pieceIndex != 8) return;
4968           return address;
4969         };
4970
4971         var findLongestZeroSequence = function (ipv6) {
4972           var maxIndex = null;
4973           var maxLength = 1;
4974           var currStart = null;
4975           var currLength = 0;
4976           var index = 0;
4977           for (; index < 8; index++) {
4978             if (ipv6[index] !== 0) {
4979               if (currLength > maxLength) {
4980                 maxIndex = currStart;
4981                 maxLength = currLength;
4982               }
4983               currStart = null;
4984               currLength = 0;
4985             } else {
4986               if (currStart === null) currStart = index;
4987               ++currLength;
4988             }
4989           }
4990           if (currLength > maxLength) {
4991             maxIndex = currStart;
4992             maxLength = currLength;
4993           }
4994           return maxIndex;
4995         };
4996
4997         var serializeHost = function (host) {
4998           var result, index, compress, ignore0;
4999           // ipv4
5000           if (typeof host == 'number') {
5001             result = [];
5002             for (index = 0; index < 4; index++) {
5003               result.unshift(host % 256);
5004               host = floor$2(host / 256);
5005             } return result.join('.');
5006           // ipv6
5007           } else if (typeof host == 'object') {
5008             result = '';
5009             compress = findLongestZeroSequence(host);
5010             for (index = 0; index < 8; index++) {
5011               if (ignore0 && host[index] === 0) continue;
5012               if (ignore0) ignore0 = false;
5013               if (compress === index) {
5014                 result += index ? ':' : '::';
5015                 ignore0 = true;
5016               } else {
5017                 result += host[index].toString(16);
5018                 if (index < 7) result += ':';
5019               }
5020             }
5021             return '[' + result + ']';
5022           } return host;
5023         };
5024
5025         var C0ControlPercentEncodeSet = {};
5026         var fragmentPercentEncodeSet = objectAssign({}, C0ControlPercentEncodeSet, {
5027           ' ': 1, '"': 1, '<': 1, '>': 1, '`': 1
5028         });
5029         var pathPercentEncodeSet = objectAssign({}, fragmentPercentEncodeSet, {
5030           '#': 1, '?': 1, '{': 1, '}': 1
5031         });
5032         var userinfoPercentEncodeSet = objectAssign({}, pathPercentEncodeSet, {
5033           '/': 1, ':': 1, ';': 1, '=': 1, '@': 1, '[': 1, '\\': 1, ']': 1, '^': 1, '|': 1
5034         });
5035
5036         var percentEncode = function (char, set) {
5037           var code = codeAt(char, 0);
5038           return code > 0x20 && code < 0x7F && !has$1(set, char) ? char : encodeURIComponent(char);
5039         };
5040
5041         var specialSchemes = {
5042           ftp: 21,
5043           file: null,
5044           http: 80,
5045           https: 443,
5046           ws: 80,
5047           wss: 443
5048         };
5049
5050         var isSpecial = function (url) {
5051           return has$1(specialSchemes, url.scheme);
5052         };
5053
5054         var includesCredentials = function (url) {
5055           return url.username != '' || url.password != '';
5056         };
5057
5058         var cannotHaveUsernamePasswordPort = function (url) {
5059           return !url.host || url.cannotBeABaseURL || url.scheme == 'file';
5060         };
5061
5062         var isWindowsDriveLetter = function (string, normalized) {
5063           var second;
5064           return string.length == 2 && ALPHA.test(string.charAt(0))
5065             && ((second = string.charAt(1)) == ':' || (!normalized && second == '|'));
5066         };
5067
5068         var startsWithWindowsDriveLetter = function (string) {
5069           var third;
5070           return string.length > 1 && isWindowsDriveLetter(string.slice(0, 2)) && (
5071             string.length == 2 ||
5072             ((third = string.charAt(2)) === '/' || third === '\\' || third === '?' || third === '#')
5073           );
5074         };
5075
5076         var shortenURLsPath = function (url) {
5077           var path = url.path;
5078           var pathSize = path.length;
5079           if (pathSize && (url.scheme != 'file' || pathSize != 1 || !isWindowsDriveLetter(path[0], true))) {
5080             path.pop();
5081           }
5082         };
5083
5084         var isSingleDot = function (segment) {
5085           return segment === '.' || segment.toLowerCase() === '%2e';
5086         };
5087
5088         var isDoubleDot = function (segment) {
5089           segment = segment.toLowerCase();
5090           return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
5091         };
5092
5093         // States:
5094         var SCHEME_START = {};
5095         var SCHEME = {};
5096         var NO_SCHEME = {};
5097         var SPECIAL_RELATIVE_OR_AUTHORITY = {};
5098         var PATH_OR_AUTHORITY = {};
5099         var RELATIVE = {};
5100         var RELATIVE_SLASH = {};
5101         var SPECIAL_AUTHORITY_SLASHES = {};
5102         var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
5103         var AUTHORITY = {};
5104         var HOST = {};
5105         var HOSTNAME = {};
5106         var PORT = {};
5107         var FILE = {};
5108         var FILE_SLASH = {};
5109         var FILE_HOST = {};
5110         var PATH_START = {};
5111         var PATH = {};
5112         var CANNOT_BE_A_BASE_URL_PATH = {};
5113         var QUERY = {};
5114         var FRAGMENT = {};
5115
5116         // eslint-disable-next-line max-statements -- TODO
5117         var parseURL = function (url, input, stateOverride, base) {
5118           var state = stateOverride || SCHEME_START;
5119           var pointer = 0;
5120           var buffer = '';
5121           var seenAt = false;
5122           var seenBracket = false;
5123           var seenPasswordToken = false;
5124           var codePoints, char, bufferCodePoints, failure;
5125
5126           if (!stateOverride) {
5127             url.scheme = '';
5128             url.username = '';
5129             url.password = '';
5130             url.host = null;
5131             url.port = null;
5132             url.path = [];
5133             url.query = null;
5134             url.fragment = null;
5135             url.cannotBeABaseURL = false;
5136             input = input.replace(LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE, '');
5137           }
5138
5139           input = input.replace(TAB_AND_NEW_LINE, '');
5140
5141           codePoints = arrayFrom(input);
5142
5143           while (pointer <= codePoints.length) {
5144             char = codePoints[pointer];
5145             switch (state) {
5146               case SCHEME_START:
5147                 if (char && ALPHA.test(char)) {
5148                   buffer += char.toLowerCase();
5149                   state = SCHEME;
5150                 } else if (!stateOverride) {
5151                   state = NO_SCHEME;
5152                   continue;
5153                 } else return INVALID_SCHEME;
5154                 break;
5155
5156               case SCHEME:
5157                 if (char && (ALPHANUMERIC.test(char) || char == '+' || char == '-' || char == '.')) {
5158                   buffer += char.toLowerCase();
5159                 } else if (char == ':') {
5160                   if (stateOverride && (
5161                     (isSpecial(url) != has$1(specialSchemes, buffer)) ||
5162                     (buffer == 'file' && (includesCredentials(url) || url.port !== null)) ||
5163                     (url.scheme == 'file' && !url.host)
5164                   )) return;
5165                   url.scheme = buffer;
5166                   if (stateOverride) {
5167                     if (isSpecial(url) && specialSchemes[url.scheme] == url.port) url.port = null;
5168                     return;
5169                   }
5170                   buffer = '';
5171                   if (url.scheme == 'file') {
5172                     state = FILE;
5173                   } else if (isSpecial(url) && base && base.scheme == url.scheme) {
5174                     state = SPECIAL_RELATIVE_OR_AUTHORITY;
5175                   } else if (isSpecial(url)) {
5176                     state = SPECIAL_AUTHORITY_SLASHES;
5177                   } else if (codePoints[pointer + 1] == '/') {
5178                     state = PATH_OR_AUTHORITY;
5179                     pointer++;
5180                   } else {
5181                     url.cannotBeABaseURL = true;
5182                     url.path.push('');
5183                     state = CANNOT_BE_A_BASE_URL_PATH;
5184                   }
5185                 } else if (!stateOverride) {
5186                   buffer = '';
5187                   state = NO_SCHEME;
5188                   pointer = 0;
5189                   continue;
5190                 } else return INVALID_SCHEME;
5191                 break;
5192
5193               case NO_SCHEME:
5194                 if (!base || (base.cannotBeABaseURL && char != '#')) return INVALID_SCHEME;
5195                 if (base.cannotBeABaseURL && char == '#') {
5196                   url.scheme = base.scheme;
5197                   url.path = base.path.slice();
5198                   url.query = base.query;
5199                   url.fragment = '';
5200                   url.cannotBeABaseURL = true;
5201                   state = FRAGMENT;
5202                   break;
5203                 }
5204                 state = base.scheme == 'file' ? FILE : RELATIVE;
5205                 continue;
5206
5207               case SPECIAL_RELATIVE_OR_AUTHORITY:
5208                 if (char == '/' && codePoints[pointer + 1] == '/') {
5209                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5210                   pointer++;
5211                 } else {
5212                   state = RELATIVE;
5213                   continue;
5214                 } break;
5215
5216               case PATH_OR_AUTHORITY:
5217                 if (char == '/') {
5218                   state = AUTHORITY;
5219                   break;
5220                 } else {
5221                   state = PATH;
5222                   continue;
5223                 }
5224
5225               case RELATIVE:
5226                 url.scheme = base.scheme;
5227                 if (char == EOF) {
5228                   url.username = base.username;
5229                   url.password = base.password;
5230                   url.host = base.host;
5231                   url.port = base.port;
5232                   url.path = base.path.slice();
5233                   url.query = base.query;
5234                 } else if (char == '/' || (char == '\\' && isSpecial(url))) {
5235                   state = RELATIVE_SLASH;
5236                 } else if (char == '?') {
5237                   url.username = base.username;
5238                   url.password = base.password;
5239                   url.host = base.host;
5240                   url.port = base.port;
5241                   url.path = base.path.slice();
5242                   url.query = '';
5243                   state = QUERY;
5244                 } else if (char == '#') {
5245                   url.username = base.username;
5246                   url.password = base.password;
5247                   url.host = base.host;
5248                   url.port = base.port;
5249                   url.path = base.path.slice();
5250                   url.query = base.query;
5251                   url.fragment = '';
5252                   state = FRAGMENT;
5253                 } else {
5254                   url.username = base.username;
5255                   url.password = base.password;
5256                   url.host = base.host;
5257                   url.port = base.port;
5258                   url.path = base.path.slice();
5259                   url.path.pop();
5260                   state = PATH;
5261                   continue;
5262                 } break;
5263
5264               case RELATIVE_SLASH:
5265                 if (isSpecial(url) && (char == '/' || char == '\\')) {
5266                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5267                 } else if (char == '/') {
5268                   state = AUTHORITY;
5269                 } else {
5270                   url.username = base.username;
5271                   url.password = base.password;
5272                   url.host = base.host;
5273                   url.port = base.port;
5274                   state = PATH;
5275                   continue;
5276                 } break;
5277
5278               case SPECIAL_AUTHORITY_SLASHES:
5279                 state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5280                 if (char != '/' || buffer.charAt(pointer + 1) != '/') continue;
5281                 pointer++;
5282                 break;
5283
5284               case SPECIAL_AUTHORITY_IGNORE_SLASHES:
5285                 if (char != '/' && char != '\\') {
5286                   state = AUTHORITY;
5287                   continue;
5288                 } break;
5289
5290               case AUTHORITY:
5291                 if (char == '@') {
5292                   if (seenAt) buffer = '%40' + buffer;
5293                   seenAt = true;
5294                   bufferCodePoints = arrayFrom(buffer);
5295                   for (var i = 0; i < bufferCodePoints.length; i++) {
5296                     var codePoint = bufferCodePoints[i];
5297                     if (codePoint == ':' && !seenPasswordToken) {
5298                       seenPasswordToken = true;
5299                       continue;
5300                     }
5301                     var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
5302                     if (seenPasswordToken) url.password += encodedCodePoints;
5303                     else url.username += encodedCodePoints;
5304                   }
5305                   buffer = '';
5306                 } else if (
5307                   char == EOF || char == '/' || char == '?' || char == '#' ||
5308                   (char == '\\' && isSpecial(url))
5309                 ) {
5310                   if (seenAt && buffer == '') return INVALID_AUTHORITY;
5311                   pointer -= arrayFrom(buffer).length + 1;
5312                   buffer = '';
5313                   state = HOST;
5314                 } else buffer += char;
5315                 break;
5316
5317               case HOST:
5318               case HOSTNAME:
5319                 if (stateOverride && url.scheme == 'file') {
5320                   state = FILE_HOST;
5321                   continue;
5322                 } else if (char == ':' && !seenBracket) {
5323                   if (buffer == '') return INVALID_HOST;
5324                   failure = parseHost(url, buffer);
5325                   if (failure) return failure;
5326                   buffer = '';
5327                   state = PORT;
5328                   if (stateOverride == HOSTNAME) return;
5329                 } else if (
5330                   char == EOF || char == '/' || char == '?' || char == '#' ||
5331                   (char == '\\' && isSpecial(url))
5332                 ) {
5333                   if (isSpecial(url) && buffer == '') return INVALID_HOST;
5334                   if (stateOverride && buffer == '' && (includesCredentials(url) || url.port !== null)) return;
5335                   failure = parseHost(url, buffer);
5336                   if (failure) return failure;
5337                   buffer = '';
5338                   state = PATH_START;
5339                   if (stateOverride) return;
5340                   continue;
5341                 } else {
5342                   if (char == '[') seenBracket = true;
5343                   else if (char == ']') seenBracket = false;
5344                   buffer += char;
5345                 } break;
5346
5347               case PORT:
5348                 if (DIGIT.test(char)) {
5349                   buffer += char;
5350                 } else if (
5351                   char == EOF || char == '/' || char == '?' || char == '#' ||
5352                   (char == '\\' && isSpecial(url)) ||
5353                   stateOverride
5354                 ) {
5355                   if (buffer != '') {
5356                     var port = parseInt(buffer, 10);
5357                     if (port > 0xFFFF) return INVALID_PORT;
5358                     url.port = (isSpecial(url) && port === specialSchemes[url.scheme]) ? null : port;
5359                     buffer = '';
5360                   }
5361                   if (stateOverride) return;
5362                   state = PATH_START;
5363                   continue;
5364                 } else return INVALID_PORT;
5365                 break;
5366
5367               case FILE:
5368                 url.scheme = 'file';
5369                 if (char == '/' || char == '\\') state = FILE_SLASH;
5370                 else if (base && base.scheme == 'file') {
5371                   if (char == EOF) {
5372                     url.host = base.host;
5373                     url.path = base.path.slice();
5374                     url.query = base.query;
5375                   } else if (char == '?') {
5376                     url.host = base.host;
5377                     url.path = base.path.slice();
5378                     url.query = '';
5379                     state = QUERY;
5380                   } else if (char == '#') {
5381                     url.host = base.host;
5382                     url.path = base.path.slice();
5383                     url.query = base.query;
5384                     url.fragment = '';
5385                     state = FRAGMENT;
5386                   } else {
5387                     if (!startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5388                       url.host = base.host;
5389                       url.path = base.path.slice();
5390                       shortenURLsPath(url);
5391                     }
5392                     state = PATH;
5393                     continue;
5394                   }
5395                 } else {
5396                   state = PATH;
5397                   continue;
5398                 } break;
5399
5400               case FILE_SLASH:
5401                 if (char == '/' || char == '\\') {
5402                   state = FILE_HOST;
5403                   break;
5404                 }
5405                 if (base && base.scheme == 'file' && !startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5406                   if (isWindowsDriveLetter(base.path[0], true)) url.path.push(base.path[0]);
5407                   else url.host = base.host;
5408                 }
5409                 state = PATH;
5410                 continue;
5411
5412               case FILE_HOST:
5413                 if (char == EOF || char == '/' || char == '\\' || char == '?' || char == '#') {
5414                   if (!stateOverride && isWindowsDriveLetter(buffer)) {
5415                     state = PATH;
5416                   } else if (buffer == '') {
5417                     url.host = '';
5418                     if (stateOverride) return;
5419                     state = PATH_START;
5420                   } else {
5421                     failure = parseHost(url, buffer);
5422                     if (failure) return failure;
5423                     if (url.host == 'localhost') url.host = '';
5424                     if (stateOverride) return;
5425                     buffer = '';
5426                     state = PATH_START;
5427                   } continue;
5428                 } else buffer += char;
5429                 break;
5430
5431               case PATH_START:
5432                 if (isSpecial(url)) {
5433                   state = PATH;
5434                   if (char != '/' && char != '\\') continue;
5435                 } else if (!stateOverride && char == '?') {
5436                   url.query = '';
5437                   state = QUERY;
5438                 } else if (!stateOverride && char == '#') {
5439                   url.fragment = '';
5440                   state = FRAGMENT;
5441                 } else if (char != EOF) {
5442                   state = PATH;
5443                   if (char != '/') continue;
5444                 } break;
5445
5446               case PATH:
5447                 if (
5448                   char == EOF || char == '/' ||
5449                   (char == '\\' && isSpecial(url)) ||
5450                   (!stateOverride && (char == '?' || char == '#'))
5451                 ) {
5452                   if (isDoubleDot(buffer)) {
5453                     shortenURLsPath(url);
5454                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5455                       url.path.push('');
5456                     }
5457                   } else if (isSingleDot(buffer)) {
5458                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5459                       url.path.push('');
5460                     }
5461                   } else {
5462                     if (url.scheme == 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
5463                       if (url.host) url.host = '';
5464                       buffer = buffer.charAt(0) + ':'; // normalize windows drive letter
5465                     }
5466                     url.path.push(buffer);
5467                   }
5468                   buffer = '';
5469                   if (url.scheme == 'file' && (char == EOF || char == '?' || char == '#')) {
5470                     while (url.path.length > 1 && url.path[0] === '') {
5471                       url.path.shift();
5472                     }
5473                   }
5474                   if (char == '?') {
5475                     url.query = '';
5476                     state = QUERY;
5477                   } else if (char == '#') {
5478                     url.fragment = '';
5479                     state = FRAGMENT;
5480                   }
5481                 } else {
5482                   buffer += percentEncode(char, pathPercentEncodeSet);
5483                 } break;
5484
5485               case CANNOT_BE_A_BASE_URL_PATH:
5486                 if (char == '?') {
5487                   url.query = '';
5488                   state = QUERY;
5489                 } else if (char == '#') {
5490                   url.fragment = '';
5491                   state = FRAGMENT;
5492                 } else if (char != EOF) {
5493                   url.path[0] += percentEncode(char, C0ControlPercentEncodeSet);
5494                 } break;
5495
5496               case QUERY:
5497                 if (!stateOverride && char == '#') {
5498                   url.fragment = '';
5499                   state = FRAGMENT;
5500                 } else if (char != EOF) {
5501                   if (char == "'" && isSpecial(url)) url.query += '%27';
5502                   else if (char == '#') url.query += '%23';
5503                   else url.query += percentEncode(char, C0ControlPercentEncodeSet);
5504                 } break;
5505
5506               case FRAGMENT:
5507                 if (char != EOF) url.fragment += percentEncode(char, fragmentPercentEncodeSet);
5508                 break;
5509             }
5510
5511             pointer++;
5512           }
5513         };
5514
5515         // `URL` constructor
5516         // https://url.spec.whatwg.org/#url-class
5517         var URLConstructor = function URL(url /* , base */) {
5518           var that = anInstance(this, URLConstructor, 'URL');
5519           var base = arguments.length > 1 ? arguments[1] : undefined;
5520           var urlString = String(url);
5521           var state = setInternalState$1(that, { type: 'URL' });
5522           var baseState, failure;
5523           if (base !== undefined) {
5524             if (base instanceof URLConstructor) baseState = getInternalURLState(base);
5525             else {
5526               failure = parseURL(baseState = {}, String(base));
5527               if (failure) throw TypeError(failure);
5528             }
5529           }
5530           failure = parseURL(state, urlString, null, baseState);
5531           if (failure) throw TypeError(failure);
5532           var searchParams = state.searchParams = new URLSearchParams$1();
5533           var searchParamsState = getInternalSearchParamsState(searchParams);
5534           searchParamsState.updateSearchParams(state.query);
5535           searchParamsState.updateURL = function () {
5536             state.query = String(searchParams) || null;
5537           };
5538           if (!descriptors) {
5539             that.href = serializeURL.call(that);
5540             that.origin = getOrigin.call(that);
5541             that.protocol = getProtocol.call(that);
5542             that.username = getUsername.call(that);
5543             that.password = getPassword.call(that);
5544             that.host = getHost.call(that);
5545             that.hostname = getHostname.call(that);
5546             that.port = getPort.call(that);
5547             that.pathname = getPathname.call(that);
5548             that.search = getSearch.call(that);
5549             that.searchParams = getSearchParams.call(that);
5550             that.hash = getHash.call(that);
5551           }
5552         };
5553
5554         var URLPrototype = URLConstructor.prototype;
5555
5556         var serializeURL = function () {
5557           var url = getInternalURLState(this);
5558           var scheme = url.scheme;
5559           var username = url.username;
5560           var password = url.password;
5561           var host = url.host;
5562           var port = url.port;
5563           var path = url.path;
5564           var query = url.query;
5565           var fragment = url.fragment;
5566           var output = scheme + ':';
5567           if (host !== null) {
5568             output += '//';
5569             if (includesCredentials(url)) {
5570               output += username + (password ? ':' + password : '') + '@';
5571             }
5572             output += serializeHost(host);
5573             if (port !== null) output += ':' + port;
5574           } else if (scheme == 'file') output += '//';
5575           output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
5576           if (query !== null) output += '?' + query;
5577           if (fragment !== null) output += '#' + fragment;
5578           return output;
5579         };
5580
5581         var getOrigin = function () {
5582           var url = getInternalURLState(this);
5583           var scheme = url.scheme;
5584           var port = url.port;
5585           if (scheme == 'blob') try {
5586             return new URLConstructor(scheme.path[0]).origin;
5587           } catch (error) {
5588             return 'null';
5589           }
5590           if (scheme == 'file' || !isSpecial(url)) return 'null';
5591           return scheme + '://' + serializeHost(url.host) + (port !== null ? ':' + port : '');
5592         };
5593
5594         var getProtocol = function () {
5595           return getInternalURLState(this).scheme + ':';
5596         };
5597
5598         var getUsername = function () {
5599           return getInternalURLState(this).username;
5600         };
5601
5602         var getPassword = function () {
5603           return getInternalURLState(this).password;
5604         };
5605
5606         var getHost = function () {
5607           var url = getInternalURLState(this);
5608           var host = url.host;
5609           var port = url.port;
5610           return host === null ? ''
5611             : port === null ? serializeHost(host)
5612             : serializeHost(host) + ':' + port;
5613         };
5614
5615         var getHostname = function () {
5616           var host = getInternalURLState(this).host;
5617           return host === null ? '' : serializeHost(host);
5618         };
5619
5620         var getPort = function () {
5621           var port = getInternalURLState(this).port;
5622           return port === null ? '' : String(port);
5623         };
5624
5625         var getPathname = function () {
5626           var url = getInternalURLState(this);
5627           var path = url.path;
5628           return url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
5629         };
5630
5631         var getSearch = function () {
5632           var query = getInternalURLState(this).query;
5633           return query ? '?' + query : '';
5634         };
5635
5636         var getSearchParams = function () {
5637           return getInternalURLState(this).searchParams;
5638         };
5639
5640         var getHash = function () {
5641           var fragment = getInternalURLState(this).fragment;
5642           return fragment ? '#' + fragment : '';
5643         };
5644
5645         var accessorDescriptor = function (getter, setter) {
5646           return { get: getter, set: setter, configurable: true, enumerable: true };
5647         };
5648
5649         if (descriptors) {
5650           objectDefineProperties(URLPrototype, {
5651             // `URL.prototype.href` accessors pair
5652             // https://url.spec.whatwg.org/#dom-url-href
5653             href: accessorDescriptor(serializeURL, function (href) {
5654               var url = getInternalURLState(this);
5655               var urlString = String(href);
5656               var failure = parseURL(url, urlString);
5657               if (failure) throw TypeError(failure);
5658               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
5659             }),
5660             // `URL.prototype.origin` getter
5661             // https://url.spec.whatwg.org/#dom-url-origin
5662             origin: accessorDescriptor(getOrigin),
5663             // `URL.prototype.protocol` accessors pair
5664             // https://url.spec.whatwg.org/#dom-url-protocol
5665             protocol: accessorDescriptor(getProtocol, function (protocol) {
5666               var url = getInternalURLState(this);
5667               parseURL(url, String(protocol) + ':', SCHEME_START);
5668             }),
5669             // `URL.prototype.username` accessors pair
5670             // https://url.spec.whatwg.org/#dom-url-username
5671             username: accessorDescriptor(getUsername, function (username) {
5672               var url = getInternalURLState(this);
5673               var codePoints = arrayFrom(String(username));
5674               if (cannotHaveUsernamePasswordPort(url)) return;
5675               url.username = '';
5676               for (var i = 0; i < codePoints.length; i++) {
5677                 url.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
5678               }
5679             }),
5680             // `URL.prototype.password` accessors pair
5681             // https://url.spec.whatwg.org/#dom-url-password
5682             password: accessorDescriptor(getPassword, function (password) {
5683               var url = getInternalURLState(this);
5684               var codePoints = arrayFrom(String(password));
5685               if (cannotHaveUsernamePasswordPort(url)) return;
5686               url.password = '';
5687               for (var i = 0; i < codePoints.length; i++) {
5688                 url.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
5689               }
5690             }),
5691             // `URL.prototype.host` accessors pair
5692             // https://url.spec.whatwg.org/#dom-url-host
5693             host: accessorDescriptor(getHost, function (host) {
5694               var url = getInternalURLState(this);
5695               if (url.cannotBeABaseURL) return;
5696               parseURL(url, String(host), HOST);
5697             }),
5698             // `URL.prototype.hostname` accessors pair
5699             // https://url.spec.whatwg.org/#dom-url-hostname
5700             hostname: accessorDescriptor(getHostname, function (hostname) {
5701               var url = getInternalURLState(this);
5702               if (url.cannotBeABaseURL) return;
5703               parseURL(url, String(hostname), HOSTNAME);
5704             }),
5705             // `URL.prototype.port` accessors pair
5706             // https://url.spec.whatwg.org/#dom-url-port
5707             port: accessorDescriptor(getPort, function (port) {
5708               var url = getInternalURLState(this);
5709               if (cannotHaveUsernamePasswordPort(url)) return;
5710               port = String(port);
5711               if (port == '') url.port = null;
5712               else parseURL(url, port, PORT);
5713             }),
5714             // `URL.prototype.pathname` accessors pair
5715             // https://url.spec.whatwg.org/#dom-url-pathname
5716             pathname: accessorDescriptor(getPathname, function (pathname) {
5717               var url = getInternalURLState(this);
5718               if (url.cannotBeABaseURL) return;
5719               url.path = [];
5720               parseURL(url, pathname + '', PATH_START);
5721             }),
5722             // `URL.prototype.search` accessors pair
5723             // https://url.spec.whatwg.org/#dom-url-search
5724             search: accessorDescriptor(getSearch, function (search) {
5725               var url = getInternalURLState(this);
5726               search = String(search);
5727               if (search == '') {
5728                 url.query = null;
5729               } else {
5730                 if ('?' == search.charAt(0)) search = search.slice(1);
5731                 url.query = '';
5732                 parseURL(url, search, QUERY);
5733               }
5734               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
5735             }),
5736             // `URL.prototype.searchParams` getter
5737             // https://url.spec.whatwg.org/#dom-url-searchparams
5738             searchParams: accessorDescriptor(getSearchParams),
5739             // `URL.prototype.hash` accessors pair
5740             // https://url.spec.whatwg.org/#dom-url-hash
5741             hash: accessorDescriptor(getHash, function (hash) {
5742               var url = getInternalURLState(this);
5743               hash = String(hash);
5744               if (hash == '') {
5745                 url.fragment = null;
5746                 return;
5747               }
5748               if ('#' == hash.charAt(0)) hash = hash.slice(1);
5749               url.fragment = '';
5750               parseURL(url, hash, FRAGMENT);
5751             })
5752           });
5753         }
5754
5755         // `URL.prototype.toJSON` method
5756         // https://url.spec.whatwg.org/#dom-url-tojson
5757         redefine(URLPrototype, 'toJSON', function toJSON() {
5758           return serializeURL.call(this);
5759         }, { enumerable: true });
5760
5761         // `URL.prototype.toString` method
5762         // https://url.spec.whatwg.org/#URL-stringification-behavior
5763         redefine(URLPrototype, 'toString', function toString() {
5764           return serializeURL.call(this);
5765         }, { enumerable: true });
5766
5767         if (NativeURL) {
5768           var nativeCreateObjectURL = NativeURL.createObjectURL;
5769           var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
5770           // `URL.createObjectURL` method
5771           // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
5772           // eslint-disable-next-line no-unused-vars -- required for `.length`
5773           if (nativeCreateObjectURL) redefine(URLConstructor, 'createObjectURL', function createObjectURL(blob) {
5774             return nativeCreateObjectURL.apply(NativeURL, arguments);
5775           });
5776           // `URL.revokeObjectURL` method
5777           // https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
5778           // eslint-disable-next-line no-unused-vars -- required for `.length`
5779           if (nativeRevokeObjectURL) redefine(URLConstructor, 'revokeObjectURL', function revokeObjectURL(url) {
5780             return nativeRevokeObjectURL.apply(NativeURL, arguments);
5781           });
5782         }
5783
5784         setToStringTag(URLConstructor, 'URL');
5785
5786         _export({ global: true, forced: !nativeUrl, sham: !descriptors }, {
5787           URL: URLConstructor
5788         });
5789
5790         // `RegExp.prototype.flags` getter implementation
5791         // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
5792         var regexpFlags = function () {
5793           var that = anObject(this);
5794           var result = '';
5795           if (that.global) result += 'g';
5796           if (that.ignoreCase) result += 'i';
5797           if (that.multiline) result += 'm';
5798           if (that.dotAll) result += 's';
5799           if (that.unicode) result += 'u';
5800           if (that.sticky) result += 'y';
5801           return result;
5802         };
5803
5804         var TO_STRING = 'toString';
5805         var RegExpPrototype$2 = RegExp.prototype;
5806         var nativeToString = RegExpPrototype$2[TO_STRING];
5807
5808         var NOT_GENERIC = fails(function () { return nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'; });
5809         // FF44- RegExp#toString has a wrong name
5810         var INCORRECT_NAME = nativeToString.name != TO_STRING;
5811
5812         // `RegExp.prototype.toString` method
5813         // https://tc39.es/ecma262/#sec-regexp.prototype.tostring
5814         if (NOT_GENERIC || INCORRECT_NAME) {
5815           redefine(RegExp.prototype, TO_STRING, function toString() {
5816             var R = anObject(this);
5817             var p = String(R.source);
5818             var rf = R.flags;
5819             var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype$2) ? regexpFlags.call(R) : rf);
5820             return '/' + p + '/' + f;
5821           }, { unsafe: true });
5822         }
5823
5824         // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError,
5825         var RE = function (s, f) {
5826           return RegExp(s, f);
5827         };
5828
5829         var UNSUPPORTED_Y$3 = fails(function () {
5830           var re = RE('a', 'y');
5831           re.lastIndex = 2;
5832           return re.exec('abcd') != null;
5833         });
5834
5835         var BROKEN_CARET = fails(function () {
5836           // https://bugzilla.mozilla.org/show_bug.cgi?id=773687
5837           var re = RE('^r', 'gy');
5838           re.lastIndex = 2;
5839           return re.exec('str') != null;
5840         });
5841
5842         var regexpStickyHelpers = {
5843                 UNSUPPORTED_Y: UNSUPPORTED_Y$3,
5844                 BROKEN_CARET: BROKEN_CARET
5845         };
5846
5847         var regexpUnsupportedDotAll = fails(function () {
5848           // babel-minify transpiles RegExp('.', 's') -> /./s and it causes SyntaxError
5849           var re = RegExp('.', (typeof '').charAt(0));
5850           return !(re.dotAll && re.exec('\n') && re.flags === 's');
5851         });
5852
5853         var regexpUnsupportedNcg = fails(function () {
5854           // babel-minify transpiles RegExp('.', 'g') -> /./g and it causes SyntaxError
5855           var re = RegExp('(?<a>b)', (typeof '').charAt(5));
5856           return re.exec('b').groups.a !== 'b' ||
5857             'b'.replace(re, '$<a>c') !== 'bc';
5858         });
5859
5860         /* eslint-disable regexp/no-assertion-capturing-group, regexp/no-empty-group, regexp/no-lazy-ends -- testing */
5861         /* eslint-disable regexp/no-useless-quantifier -- testing */
5862
5863
5864
5865
5866         var getInternalState = internalState.get;
5867
5868
5869
5870         var nativeExec = RegExp.prototype.exec;
5871         var nativeReplace = shared('native-string-replace', String.prototype.replace);
5872
5873         var patchedExec = nativeExec;
5874
5875         var UPDATES_LAST_INDEX_WRONG = (function () {
5876           var re1 = /a/;
5877           var re2 = /b*/g;
5878           nativeExec.call(re1, 'a');
5879           nativeExec.call(re2, 'a');
5880           return re1.lastIndex !== 0 || re2.lastIndex !== 0;
5881         })();
5882
5883         var UNSUPPORTED_Y$2 = regexpStickyHelpers.UNSUPPORTED_Y || regexpStickyHelpers.BROKEN_CARET;
5884
5885         // nonparticipating capturing group, copied from es5-shim's String#split patch.
5886         var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
5887
5888         var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$2 || regexpUnsupportedDotAll || regexpUnsupportedNcg;
5889
5890         if (PATCH) {
5891           // eslint-disable-next-line max-statements -- TODO
5892           patchedExec = function exec(str) {
5893             var re = this;
5894             var state = getInternalState(re);
5895             var raw = state.raw;
5896             var result, reCopy, lastIndex, match, i, object, group;
5897
5898             if (raw) {
5899               raw.lastIndex = re.lastIndex;
5900               result = patchedExec.call(raw, str);
5901               re.lastIndex = raw.lastIndex;
5902               return result;
5903             }
5904
5905             var groups = state.groups;
5906             var sticky = UNSUPPORTED_Y$2 && re.sticky;
5907             var flags = regexpFlags.call(re);
5908             var source = re.source;
5909             var charsAdded = 0;
5910             var strCopy = str;
5911
5912             if (sticky) {
5913               flags = flags.replace('y', '');
5914               if (flags.indexOf('g') === -1) {
5915                 flags += 'g';
5916               }
5917
5918               strCopy = String(str).slice(re.lastIndex);
5919               // Support anchored sticky behavior.
5920               if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) {
5921                 source = '(?: ' + source + ')';
5922                 strCopy = ' ' + strCopy;
5923                 charsAdded++;
5924               }
5925               // ^(? + rx + ) is needed, in combination with some str slicing, to
5926               // simulate the 'y' flag.
5927               reCopy = new RegExp('^(?:' + source + ')', flags);
5928             }
5929
5930             if (NPCG_INCLUDED) {
5931               reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
5932             }
5933             if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
5934
5935             match = nativeExec.call(sticky ? reCopy : re, strCopy);
5936
5937             if (sticky) {
5938               if (match) {
5939                 match.input = match.input.slice(charsAdded);
5940                 match[0] = match[0].slice(charsAdded);
5941                 match.index = re.lastIndex;
5942                 re.lastIndex += match[0].length;
5943               } else re.lastIndex = 0;
5944             } else if (UPDATES_LAST_INDEX_WRONG && match) {
5945               re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
5946             }
5947             if (NPCG_INCLUDED && match && match.length > 1) {
5948               // Fix browsers whose `exec` methods don't consistently return `undefined`
5949               // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
5950               nativeReplace.call(match[0], reCopy, function () {
5951                 for (i = 1; i < arguments.length - 2; i++) {
5952                   if (arguments[i] === undefined) match[i] = undefined;
5953                 }
5954               });
5955             }
5956
5957             if (match && groups) {
5958               match.groups = object = objectCreate(null);
5959               for (i = 0; i < groups.length; i++) {
5960                 group = groups[i];
5961                 object[group[0]] = match[group[1]];
5962               }
5963             }
5964
5965             return match;
5966           };
5967         }
5968
5969         var regexpExec = patchedExec;
5970
5971         // `RegExp.prototype.exec` method
5972         // https://tc39.es/ecma262/#sec-regexp.prototype.exec
5973         _export({ target: 'RegExp', proto: true, forced: /./.exec !== regexpExec }, {
5974           exec: regexpExec
5975         });
5976
5977         // TODO: Remove from `core-js@4` since it's moved to entry points
5978
5979
5980
5981
5982
5983
5984
5985         var SPECIES = wellKnownSymbol('species');
5986         var RegExpPrototype$1 = RegExp.prototype;
5987
5988         var fixRegexpWellKnownSymbolLogic = function (KEY, exec, FORCED, SHAM) {
5989           var SYMBOL = wellKnownSymbol(KEY);
5990
5991           var DELEGATES_TO_SYMBOL = !fails(function () {
5992             // String methods call symbol-named RegEp methods
5993             var O = {};
5994             O[SYMBOL] = function () { return 7; };
5995             return ''[KEY](O) != 7;
5996           });
5997
5998           var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
5999             // Symbol-named RegExp methods call .exec
6000             var execCalled = false;
6001             var re = /a/;
6002
6003             if (KEY === 'split') {
6004               // We can't use real regex here since it causes deoptimization
6005               // and serious performance degradation in V8
6006               // https://github.com/zloirock/core-js/issues/306
6007               re = {};
6008               // RegExp[@@split] doesn't call the regex's exec method, but first creates
6009               // a new one. We need to return the patched regex when creating the new one.
6010               re.constructor = {};
6011               re.constructor[SPECIES] = function () { return re; };
6012               re.flags = '';
6013               re[SYMBOL] = /./[SYMBOL];
6014             }
6015
6016             re.exec = function () { execCalled = true; return null; };
6017
6018             re[SYMBOL]('');
6019             return !execCalled;
6020           });
6021
6022           if (
6023             !DELEGATES_TO_SYMBOL ||
6024             !DELEGATES_TO_EXEC ||
6025             FORCED
6026           ) {
6027             var nativeRegExpMethod = /./[SYMBOL];
6028             var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
6029               var $exec = regexp.exec;
6030               if ($exec === regexpExec || $exec === RegExpPrototype$1.exec) {
6031                 if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
6032                   // The native String method already delegates to @@method (this
6033                   // polyfilled function), leasing to infinite recursion.
6034                   // We avoid it by directly calling the native @@method method.
6035                   return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
6036                 }
6037                 return { done: true, value: nativeMethod.call(str, regexp, arg2) };
6038               }
6039               return { done: false };
6040             });
6041
6042             redefine(String.prototype, KEY, methods[0]);
6043             redefine(RegExpPrototype$1, SYMBOL, methods[1]);
6044           }
6045
6046           if (SHAM) createNonEnumerableProperty(RegExpPrototype$1[SYMBOL], 'sham', true);
6047         };
6048
6049         var charAt = stringMultibyte.charAt;
6050
6051         // `AdvanceStringIndex` abstract operation
6052         // https://tc39.es/ecma262/#sec-advancestringindex
6053         var advanceStringIndex = function (S, index, unicode) {
6054           return index + (unicode ? charAt(S, index).length : 1);
6055         };
6056
6057         var floor$1 = Math.floor;
6058         var replace = ''.replace;
6059         var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d{1,2}|<[^>]*>)/g;
6060         var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d{1,2})/g;
6061
6062         // `GetSubstitution` abstract operation
6063         // https://tc39.es/ecma262/#sec-getsubstitution
6064         var getSubstitution = function (matched, str, position, captures, namedCaptures, replacement) {
6065           var tailPos = position + matched.length;
6066           var m = captures.length;
6067           var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
6068           if (namedCaptures !== undefined) {
6069             namedCaptures = toObject(namedCaptures);
6070             symbols = SUBSTITUTION_SYMBOLS;
6071           }
6072           return replace.call(replacement, symbols, function (match, ch) {
6073             var capture;
6074             switch (ch.charAt(0)) {
6075               case '$': return '$';
6076               case '&': return matched;
6077               case '`': return str.slice(0, position);
6078               case "'": return str.slice(tailPos);
6079               case '<':
6080                 capture = namedCaptures[ch.slice(1, -1)];
6081                 break;
6082               default: // \d\d?
6083                 var n = +ch;
6084                 if (n === 0) return match;
6085                 if (n > m) {
6086                   var f = floor$1(n / 10);
6087                   if (f === 0) return match;
6088                   if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
6089                   return match;
6090                 }
6091                 capture = captures[n - 1];
6092             }
6093             return capture === undefined ? '' : capture;
6094           });
6095         };
6096
6097         // `RegExpExec` abstract operation
6098         // https://tc39.es/ecma262/#sec-regexpexec
6099         var regexpExecAbstract = function (R, S) {
6100           var exec = R.exec;
6101           if (typeof exec === 'function') {
6102             var result = exec.call(R, S);
6103             if (typeof result !== 'object') {
6104               throw TypeError('RegExp exec method returned something other than an Object or null');
6105             }
6106             return result;
6107           }
6108
6109           if (classofRaw(R) !== 'RegExp') {
6110             throw TypeError('RegExp#exec called on incompatible receiver');
6111           }
6112
6113           return regexpExec.call(R, S);
6114         };
6115
6116         var REPLACE = wellKnownSymbol('replace');
6117         var max$2 = Math.max;
6118         var min$5 = Math.min;
6119
6120         var maybeToString = function (it) {
6121           return it === undefined ? it : String(it);
6122         };
6123
6124         // IE <= 11 replaces $0 with the whole match, as if it was $&
6125         // https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0
6126         var REPLACE_KEEPS_$0 = (function () {
6127           // eslint-disable-next-line regexp/prefer-escape-replacement-dollar-char -- required for testing
6128           return 'a'.replace(/./, '$0') === '$0';
6129         })();
6130
6131         // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string
6132         var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () {
6133           if (/./[REPLACE]) {
6134             return /./[REPLACE]('a', '$0') === '';
6135           }
6136           return false;
6137         })();
6138
6139         var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
6140           var re = /./;
6141           re.exec = function () {
6142             var result = [];
6143             result.groups = { a: '7' };
6144             return result;
6145           };
6146           return ''.replace(re, '$<a>') !== '7';
6147         });
6148
6149         // @@replace logic
6150         fixRegexpWellKnownSymbolLogic('replace', function (_, nativeReplace, maybeCallNative) {
6151           var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';
6152
6153           return [
6154             // `String.prototype.replace` method
6155             // https://tc39.es/ecma262/#sec-string.prototype.replace
6156             function replace(searchValue, replaceValue) {
6157               var O = requireObjectCoercible(this);
6158               var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
6159               return replacer !== undefined
6160                 ? replacer.call(searchValue, O, replaceValue)
6161                 : nativeReplace.call(String(O), searchValue, replaceValue);
6162             },
6163             // `RegExp.prototype[@@replace]` method
6164             // https://tc39.es/ecma262/#sec-regexp.prototype-@@replace
6165             function (string, replaceValue) {
6166               if (
6167                 typeof replaceValue === 'string' &&
6168                 replaceValue.indexOf(UNSAFE_SUBSTITUTE) === -1 &&
6169                 replaceValue.indexOf('$<') === -1
6170               ) {
6171                 var res = maybeCallNative(nativeReplace, this, string, replaceValue);
6172                 if (res.done) return res.value;
6173               }
6174
6175               var rx = anObject(this);
6176               var S = String(string);
6177
6178               var functionalReplace = typeof replaceValue === 'function';
6179               if (!functionalReplace) replaceValue = String(replaceValue);
6180
6181               var global = rx.global;
6182               if (global) {
6183                 var fullUnicode = rx.unicode;
6184                 rx.lastIndex = 0;
6185               }
6186               var results = [];
6187               while (true) {
6188                 var result = regexpExecAbstract(rx, S);
6189                 if (result === null) break;
6190
6191                 results.push(result);
6192                 if (!global) break;
6193
6194                 var matchStr = String(result[0]);
6195                 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
6196               }
6197
6198               var accumulatedResult = '';
6199               var nextSourcePosition = 0;
6200               for (var i = 0; i < results.length; i++) {
6201                 result = results[i];
6202
6203                 var matched = String(result[0]);
6204                 var position = max$2(min$5(toInteger(result.index), S.length), 0);
6205                 var captures = [];
6206                 // NOTE: This is equivalent to
6207                 //   captures = result.slice(1).map(maybeToString)
6208                 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
6209                 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
6210                 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
6211                 for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
6212                 var namedCaptures = result.groups;
6213                 if (functionalReplace) {
6214                   var replacerArgs = [matched].concat(captures, position, S);
6215                   if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
6216                   var replacement = String(replaceValue.apply(undefined, replacerArgs));
6217                 } else {
6218                   replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
6219                 }
6220                 if (position >= nextSourcePosition) {
6221                   accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
6222                   nextSourcePosition = position + matched.length;
6223                 }
6224               }
6225               return accumulatedResult + S.slice(nextSourcePosition);
6226             }
6227           ];
6228         }, !REPLACE_SUPPORTS_NAMED_GROUPS || !REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE);
6229
6230         var MATCH$2 = wellKnownSymbol('match');
6231
6232         // `IsRegExp` abstract operation
6233         // https://tc39.es/ecma262/#sec-isregexp
6234         var isRegexp = function (it) {
6235           var isRegExp;
6236           return isObject$4(it) && ((isRegExp = it[MATCH$2]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
6237         };
6238
6239         var UNSUPPORTED_Y$1 = regexpStickyHelpers.UNSUPPORTED_Y;
6240         var arrayPush = [].push;
6241         var min$4 = Math.min;
6242         var MAX_UINT32 = 0xFFFFFFFF;
6243
6244         // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
6245         // Weex JS has frozen built-in prototypes, so use try / catch wrapper
6246         var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {
6247           // eslint-disable-next-line regexp/no-empty-group -- required for testing
6248           var re = /(?:)/;
6249           var originalExec = re.exec;
6250           re.exec = function () { return originalExec.apply(this, arguments); };
6251           var result = 'ab'.split(re);
6252           return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
6253         });
6254
6255         // @@split logic
6256         fixRegexpWellKnownSymbolLogic('split', function (SPLIT, nativeSplit, maybeCallNative) {
6257           var internalSplit;
6258           if (
6259             'abbc'.split(/(b)*/)[1] == 'c' ||
6260             // eslint-disable-next-line regexp/no-empty-group -- required for testing
6261             'test'.split(/(?:)/, -1).length != 4 ||
6262             'ab'.split(/(?:ab)*/).length != 2 ||
6263             '.'.split(/(.?)(.?)/).length != 4 ||
6264             // eslint-disable-next-line regexp/no-assertion-capturing-group, regexp/no-empty-group -- required for testing
6265             '.'.split(/()()/).length > 1 ||
6266             ''.split(/.?/).length
6267           ) {
6268             // based on es5-shim implementation, need to rework it
6269             internalSplit = function (separator, limit) {
6270               var string = String(requireObjectCoercible(this));
6271               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
6272               if (lim === 0) return [];
6273               if (separator === undefined) return [string];
6274               // If `separator` is not a regex, use native split
6275               if (!isRegexp(separator)) {
6276                 return nativeSplit.call(string, separator, lim);
6277               }
6278               var output = [];
6279               var flags = (separator.ignoreCase ? 'i' : '') +
6280                           (separator.multiline ? 'm' : '') +
6281                           (separator.unicode ? 'u' : '') +
6282                           (separator.sticky ? 'y' : '');
6283               var lastLastIndex = 0;
6284               // Make `global` and avoid `lastIndex` issues by working with a copy
6285               var separatorCopy = new RegExp(separator.source, flags + 'g');
6286               var match, lastIndex, lastLength;
6287               while (match = regexpExec.call(separatorCopy, string)) {
6288                 lastIndex = separatorCopy.lastIndex;
6289                 if (lastIndex > lastLastIndex) {
6290                   output.push(string.slice(lastLastIndex, match.index));
6291                   if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
6292                   lastLength = match[0].length;
6293                   lastLastIndex = lastIndex;
6294                   if (output.length >= lim) break;
6295                 }
6296                 if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
6297               }
6298               if (lastLastIndex === string.length) {
6299                 if (lastLength || !separatorCopy.test('')) output.push('');
6300               } else output.push(string.slice(lastLastIndex));
6301               return output.length > lim ? output.slice(0, lim) : output;
6302             };
6303           // Chakra, V8
6304           } else if ('0'.split(undefined, 0).length) {
6305             internalSplit = function (separator, limit) {
6306               return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
6307             };
6308           } else internalSplit = nativeSplit;
6309
6310           return [
6311             // `String.prototype.split` method
6312             // https://tc39.es/ecma262/#sec-string.prototype.split
6313             function split(separator, limit) {
6314               var O = requireObjectCoercible(this);
6315               var splitter = separator == undefined ? undefined : separator[SPLIT];
6316               return splitter !== undefined
6317                 ? splitter.call(separator, O, limit)
6318                 : internalSplit.call(String(O), separator, limit);
6319             },
6320             // `RegExp.prototype[@@split]` method
6321             // https://tc39.es/ecma262/#sec-regexp.prototype-@@split
6322             //
6323             // NOTE: This cannot be properly polyfilled in engines that don't support
6324             // the 'y' flag.
6325             function (string, limit) {
6326               var res = maybeCallNative(internalSplit, this, string, limit, internalSplit !== nativeSplit);
6327               if (res.done) return res.value;
6328
6329               var rx = anObject(this);
6330               var S = String(string);
6331               var C = speciesConstructor(rx, RegExp);
6332
6333               var unicodeMatching = rx.unicode;
6334               var flags = (rx.ignoreCase ? 'i' : '') +
6335                           (rx.multiline ? 'm' : '') +
6336                           (rx.unicode ? 'u' : '') +
6337                           (UNSUPPORTED_Y$1 ? 'g' : 'y');
6338
6339               // ^(? + rx + ) is needed, in combination with some S slicing, to
6340               // simulate the 'y' flag.
6341               var splitter = new C(UNSUPPORTED_Y$1 ? '^(?:' + rx.source + ')' : rx, flags);
6342               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
6343               if (lim === 0) return [];
6344               if (S.length === 0) return regexpExecAbstract(splitter, S) === null ? [S] : [];
6345               var p = 0;
6346               var q = 0;
6347               var A = [];
6348               while (q < S.length) {
6349                 splitter.lastIndex = UNSUPPORTED_Y$1 ? 0 : q;
6350                 var z = regexpExecAbstract(splitter, UNSUPPORTED_Y$1 ? S.slice(q) : S);
6351                 var e;
6352                 if (
6353                   z === null ||
6354                   (e = min$4(toLength(splitter.lastIndex + (UNSUPPORTED_Y$1 ? q : 0)), S.length)) === p
6355                 ) {
6356                   q = advanceStringIndex(S, q, unicodeMatching);
6357                 } else {
6358                   A.push(S.slice(p, q));
6359                   if (A.length === lim) return A;
6360                   for (var i = 1; i <= z.length - 1; i++) {
6361                     A.push(z[i]);
6362                     if (A.length === lim) return A;
6363                   }
6364                   q = p = e;
6365                 }
6366               }
6367               A.push(S.slice(p));
6368               return A;
6369             }
6370           ];
6371         }, !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC, UNSUPPORTED_Y$1);
6372
6373         // a string of all valid unicode whitespaces
6374         var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002' +
6375           '\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
6376
6377         var whitespace = '[' + whitespaces + ']';
6378         var ltrim = RegExp('^' + whitespace + whitespace + '*');
6379         var rtrim$2 = RegExp(whitespace + whitespace + '*$');
6380
6381         // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
6382         var createMethod$2 = function (TYPE) {
6383           return function ($this) {
6384             var string = String(requireObjectCoercible($this));
6385             if (TYPE & 1) string = string.replace(ltrim, '');
6386             if (TYPE & 2) string = string.replace(rtrim$2, '');
6387             return string;
6388           };
6389         };
6390
6391         var stringTrim = {
6392           // `String.prototype.{ trimLeft, trimStart }` methods
6393           // https://tc39.es/ecma262/#sec-string.prototype.trimstart
6394           start: createMethod$2(1),
6395           // `String.prototype.{ trimRight, trimEnd }` methods
6396           // https://tc39.es/ecma262/#sec-string.prototype.trimend
6397           end: createMethod$2(2),
6398           // `String.prototype.trim` method
6399           // https://tc39.es/ecma262/#sec-string.prototype.trim
6400           trim: createMethod$2(3)
6401         };
6402
6403         var non = '\u200B\u0085\u180E';
6404
6405         // check that a method works with the correct list
6406         // of whitespaces and has a correct name
6407         var stringTrimForced = function (METHOD_NAME) {
6408           return fails(function () {
6409             return !!whitespaces[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces[METHOD_NAME].name !== METHOD_NAME;
6410           });
6411         };
6412
6413         var $trim = stringTrim.trim;
6414
6415
6416         // `String.prototype.trim` method
6417         // https://tc39.es/ecma262/#sec-string.prototype.trim
6418         _export({ target: 'String', proto: true, forced: stringTrimForced('trim') }, {
6419           trim: function trim() {
6420             return $trim(this);
6421           }
6422         });
6423
6424         var defineProperty$3 = objectDefineProperty.f;
6425
6426         var FunctionPrototype = Function.prototype;
6427         var FunctionPrototypeToString = FunctionPrototype.toString;
6428         var nameRE = /^\s*function ([^ (]*)/;
6429         var NAME = 'name';
6430
6431         // Function instances `.name` property
6432         // https://tc39.es/ecma262/#sec-function-instances-name
6433         if (descriptors && !(NAME in FunctionPrototype)) {
6434           defineProperty$3(FunctionPrototype, NAME, {
6435             configurable: true,
6436             get: function () {
6437               try {
6438                 return FunctionPrototypeToString.call(this).match(nameRE)[1];
6439               } catch (error) {
6440                 return '';
6441               }
6442             }
6443           });
6444         }
6445
6446         // `Object.create` method
6447         // https://tc39.es/ecma262/#sec-object.create
6448         _export({ target: 'Object', stat: true, sham: !descriptors }, {
6449           create: objectCreate
6450         });
6451
6452         var slice$3 = [].slice;
6453         var MSIE = /MSIE .\./.test(engineUserAgent); // <- dirty ie9- check
6454
6455         var wrap$1 = function (scheduler) {
6456           return function (handler, timeout /* , ...arguments */) {
6457             var boundArgs = arguments.length > 2;
6458             var args = boundArgs ? slice$3.call(arguments, 2) : undefined;
6459             return scheduler(boundArgs ? function () {
6460               // eslint-disable-next-line no-new-func -- spec requirement
6461               (typeof handler == 'function' ? handler : Function(handler)).apply(this, args);
6462             } : handler, timeout);
6463           };
6464         };
6465
6466         // ie9- setTimeout & setInterval additional parameters fix
6467         // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
6468         _export({ global: true, bind: true, forced: MSIE }, {
6469           // `setTimeout` method
6470           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout
6471           setTimeout: wrap$1(global$2.setTimeout),
6472           // `setInterval` method
6473           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
6474           setInterval: wrap$1(global$2.setInterval)
6475         });
6476
6477         var global$1 = typeof globalThis !== 'undefined' && globalThis || typeof self !== 'undefined' && self || typeof global$1 !== 'undefined' && global$1;
6478         var support = {
6479           searchParams: 'URLSearchParams' in global$1,
6480           iterable: 'Symbol' in global$1 && 'iterator' in Symbol,
6481           blob: 'FileReader' in global$1 && 'Blob' in global$1 && function () {
6482             try {
6483               new Blob();
6484               return true;
6485             } catch (e) {
6486               return false;
6487             }
6488           }(),
6489           formData: 'FormData' in global$1,
6490           arrayBuffer: 'ArrayBuffer' in global$1
6491         };
6492
6493         function isDataView(obj) {
6494           return obj && DataView.prototype.isPrototypeOf(obj);
6495         }
6496
6497         if (support.arrayBuffer) {
6498           var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]'];
6499
6500           var isArrayBufferView = ArrayBuffer.isView || function (obj) {
6501             return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
6502           };
6503         }
6504
6505         function normalizeName(name) {
6506           if (typeof name !== 'string') {
6507             name = String(name);
6508           }
6509
6510           if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {
6511             throw new TypeError('Invalid character in header field name: "' + name + '"');
6512           }
6513
6514           return name.toLowerCase();
6515         }
6516
6517         function normalizeValue(value) {
6518           if (typeof value !== 'string') {
6519             value = String(value);
6520           }
6521
6522           return value;
6523         } // Build a destructive iterator for the value list
6524
6525
6526         function iteratorFor(items) {
6527           var iterator = {
6528             next: function next() {
6529               var value = items.shift();
6530               return {
6531                 done: value === undefined,
6532                 value: value
6533               };
6534             }
6535           };
6536
6537           if (support.iterable) {
6538             iterator[Symbol.iterator] = function () {
6539               return iterator;
6540             };
6541           }
6542
6543           return iterator;
6544         }
6545
6546         function Headers(headers) {
6547           this.map = {};
6548
6549           if (headers instanceof Headers) {
6550             headers.forEach(function (value, name) {
6551               this.append(name, value);
6552             }, this);
6553           } else if (Array.isArray(headers)) {
6554             headers.forEach(function (header) {
6555               this.append(header[0], header[1]);
6556             }, this);
6557           } else if (headers) {
6558             Object.getOwnPropertyNames(headers).forEach(function (name) {
6559               this.append(name, headers[name]);
6560             }, this);
6561           }
6562         }
6563
6564         Headers.prototype.append = function (name, value) {
6565           name = normalizeName(name);
6566           value = normalizeValue(value);
6567           var oldValue = this.map[name];
6568           this.map[name] = oldValue ? oldValue + ', ' + value : value;
6569         };
6570
6571         Headers.prototype['delete'] = function (name) {
6572           delete this.map[normalizeName(name)];
6573         };
6574
6575         Headers.prototype.get = function (name) {
6576           name = normalizeName(name);
6577           return this.has(name) ? this.map[name] : null;
6578         };
6579
6580         Headers.prototype.has = function (name) {
6581           return this.map.hasOwnProperty(normalizeName(name));
6582         };
6583
6584         Headers.prototype.set = function (name, value) {
6585           this.map[normalizeName(name)] = normalizeValue(value);
6586         };
6587
6588         Headers.prototype.forEach = function (callback, thisArg) {
6589           for (var name in this.map) {
6590             if (this.map.hasOwnProperty(name)) {
6591               callback.call(thisArg, this.map[name], name, this);
6592             }
6593           }
6594         };
6595
6596         Headers.prototype.keys = function () {
6597           var items = [];
6598           this.forEach(function (value, name) {
6599             items.push(name);
6600           });
6601           return iteratorFor(items);
6602         };
6603
6604         Headers.prototype.values = function () {
6605           var items = [];
6606           this.forEach(function (value) {
6607             items.push(value);
6608           });
6609           return iteratorFor(items);
6610         };
6611
6612         Headers.prototype.entries = function () {
6613           var items = [];
6614           this.forEach(function (value, name) {
6615             items.push([name, value]);
6616           });
6617           return iteratorFor(items);
6618         };
6619
6620         if (support.iterable) {
6621           Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
6622         }
6623
6624         function consumed(body) {
6625           if (body.bodyUsed) {
6626             return Promise.reject(new TypeError('Already read'));
6627           }
6628
6629           body.bodyUsed = true;
6630         }
6631
6632         function fileReaderReady(reader) {
6633           return new Promise(function (resolve, reject) {
6634             reader.onload = function () {
6635               resolve(reader.result);
6636             };
6637
6638             reader.onerror = function () {
6639               reject(reader.error);
6640             };
6641           });
6642         }
6643
6644         function readBlobAsArrayBuffer(blob) {
6645           var reader = new FileReader();
6646           var promise = fileReaderReady(reader);
6647           reader.readAsArrayBuffer(blob);
6648           return promise;
6649         }
6650
6651         function readBlobAsText(blob) {
6652           var reader = new FileReader();
6653           var promise = fileReaderReady(reader);
6654           reader.readAsText(blob);
6655           return promise;
6656         }
6657
6658         function readArrayBufferAsText(buf) {
6659           var view = new Uint8Array(buf);
6660           var chars = new Array(view.length);
6661
6662           for (var i = 0; i < view.length; i++) {
6663             chars[i] = String.fromCharCode(view[i]);
6664           }
6665
6666           return chars.join('');
6667         }
6668
6669         function bufferClone(buf) {
6670           if (buf.slice) {
6671             return buf.slice(0);
6672           } else {
6673             var view = new Uint8Array(buf.byteLength);
6674             view.set(new Uint8Array(buf));
6675             return view.buffer;
6676           }
6677         }
6678
6679         function Body() {
6680           this.bodyUsed = false;
6681
6682           this._initBody = function (body) {
6683             /*
6684               fetch-mock wraps the Response object in an ES6 Proxy to
6685               provide useful test harness features such as flush. However, on
6686               ES5 browsers without fetch or Proxy support pollyfills must be used;
6687               the proxy-pollyfill is unable to proxy an attribute unless it exists
6688               on the object before the Proxy is created. This change ensures
6689               Response.bodyUsed exists on the instance, while maintaining the
6690               semantic of setting Request.bodyUsed in the constructor before
6691               _initBody is called.
6692             */
6693             this.bodyUsed = this.bodyUsed;
6694             this._bodyInit = body;
6695
6696             if (!body) {
6697               this._bodyText = '';
6698             } else if (typeof body === 'string') {
6699               this._bodyText = body;
6700             } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
6701               this._bodyBlob = body;
6702             } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
6703               this._bodyFormData = body;
6704             } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
6705               this._bodyText = body.toString();
6706             } else if (support.arrayBuffer && support.blob && isDataView(body)) {
6707               this._bodyArrayBuffer = bufferClone(body.buffer); // IE 10-11 can't handle a DataView body.
6708
6709               this._bodyInit = new Blob([this._bodyArrayBuffer]);
6710             } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
6711               this._bodyArrayBuffer = bufferClone(body);
6712             } else {
6713               this._bodyText = body = Object.prototype.toString.call(body);
6714             }
6715
6716             if (!this.headers.get('content-type')) {
6717               if (typeof body === 'string') {
6718                 this.headers.set('content-type', 'text/plain;charset=UTF-8');
6719               } else if (this._bodyBlob && this._bodyBlob.type) {
6720                 this.headers.set('content-type', this._bodyBlob.type);
6721               } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
6722                 this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
6723               }
6724             }
6725           };
6726
6727           if (support.blob) {
6728             this.blob = function () {
6729               var rejected = consumed(this);
6730
6731               if (rejected) {
6732                 return rejected;
6733               }
6734
6735               if (this._bodyBlob) {
6736                 return Promise.resolve(this._bodyBlob);
6737               } else if (this._bodyArrayBuffer) {
6738                 return Promise.resolve(new Blob([this._bodyArrayBuffer]));
6739               } else if (this._bodyFormData) {
6740                 throw new Error('could not read FormData body as blob');
6741               } else {
6742                 return Promise.resolve(new Blob([this._bodyText]));
6743               }
6744             };
6745
6746             this.arrayBuffer = function () {
6747               if (this._bodyArrayBuffer) {
6748                 var isConsumed = consumed(this);
6749
6750                 if (isConsumed) {
6751                   return isConsumed;
6752                 }
6753
6754                 if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
6755                   return Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset, this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength));
6756                 } else {
6757                   return Promise.resolve(this._bodyArrayBuffer);
6758                 }
6759               } else {
6760                 return this.blob().then(readBlobAsArrayBuffer);
6761               }
6762             };
6763           }
6764
6765           this.text = function () {
6766             var rejected = consumed(this);
6767
6768             if (rejected) {
6769               return rejected;
6770             }
6771
6772             if (this._bodyBlob) {
6773               return readBlobAsText(this._bodyBlob);
6774             } else if (this._bodyArrayBuffer) {
6775               return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
6776             } else if (this._bodyFormData) {
6777               throw new Error('could not read FormData body as text');
6778             } else {
6779               return Promise.resolve(this._bodyText);
6780             }
6781           };
6782
6783           if (support.formData) {
6784             this.formData = function () {
6785               return this.text().then(decode);
6786             };
6787           }
6788
6789           this.json = function () {
6790             return this.text().then(JSON.parse);
6791           };
6792
6793           return this;
6794         } // HTTP methods whose capitalization should be normalized
6795
6796
6797         var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
6798
6799         function normalizeMethod(method) {
6800           var upcased = method.toUpperCase();
6801           return methods.indexOf(upcased) > -1 ? upcased : method;
6802         }
6803
6804         function Request(input, options) {
6805           if (!(this instanceof Request)) {
6806             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
6807           }
6808
6809           options = options || {};
6810           var body = options.body;
6811
6812           if (input instanceof Request) {
6813             if (input.bodyUsed) {
6814               throw new TypeError('Already read');
6815             }
6816
6817             this.url = input.url;
6818             this.credentials = input.credentials;
6819
6820             if (!options.headers) {
6821               this.headers = new Headers(input.headers);
6822             }
6823
6824             this.method = input.method;
6825             this.mode = input.mode;
6826             this.signal = input.signal;
6827
6828             if (!body && input._bodyInit != null) {
6829               body = input._bodyInit;
6830               input.bodyUsed = true;
6831             }
6832           } else {
6833             this.url = String(input);
6834           }
6835
6836           this.credentials = options.credentials || this.credentials || 'same-origin';
6837
6838           if (options.headers || !this.headers) {
6839             this.headers = new Headers(options.headers);
6840           }
6841
6842           this.method = normalizeMethod(options.method || this.method || 'GET');
6843           this.mode = options.mode || this.mode || null;
6844           this.signal = options.signal || this.signal;
6845           this.referrer = null;
6846
6847           if ((this.method === 'GET' || this.method === 'HEAD') && body) {
6848             throw new TypeError('Body not allowed for GET or HEAD requests');
6849           }
6850
6851           this._initBody(body);
6852
6853           if (this.method === 'GET' || this.method === 'HEAD') {
6854             if (options.cache === 'no-store' || options.cache === 'no-cache') {
6855               // Search for a '_' parameter in the query string
6856               var reParamSearch = /([?&])_=[^&]*/;
6857
6858               if (reParamSearch.test(this.url)) {
6859                 // If it already exists then set the value with the current time
6860                 this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime());
6861               } else {
6862                 // Otherwise add a new '_' parameter to the end with the current time
6863                 var reQueryString = /\?/;
6864                 this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime();
6865               }
6866             }
6867           }
6868         }
6869
6870         Request.prototype.clone = function () {
6871           return new Request(this, {
6872             body: this._bodyInit
6873           });
6874         };
6875
6876         function decode(body) {
6877           var form = new FormData();
6878           body.trim().split('&').forEach(function (bytes) {
6879             if (bytes) {
6880               var split = bytes.split('=');
6881               var name = split.shift().replace(/\+/g, ' ');
6882               var value = split.join('=').replace(/\+/g, ' ');
6883               form.append(decodeURIComponent(name), decodeURIComponent(value));
6884             }
6885           });
6886           return form;
6887         }
6888
6889         function parseHeaders(rawHeaders) {
6890           var headers = new Headers(); // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
6891           // https://tools.ietf.org/html/rfc7230#section-3.2
6892
6893           var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' '); // Avoiding split via regex to work around a common IE11 bug with the core-js 3.6.0 regex polyfill
6894           // https://github.com/github/fetch/issues/748
6895           // https://github.com/zloirock/core-js/issues/751
6896
6897           preProcessedHeaders.split('\r').map(function (header) {
6898             return header.indexOf('\n') === 0 ? header.substr(1, header.length) : header;
6899           }).forEach(function (line) {
6900             var parts = line.split(':');
6901             var key = parts.shift().trim();
6902
6903             if (key) {
6904               var value = parts.join(':').trim();
6905               headers.append(key, value);
6906             }
6907           });
6908           return headers;
6909         }
6910
6911         Body.call(Request.prototype);
6912         function Response(bodyInit, options) {
6913           if (!(this instanceof Response)) {
6914             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
6915           }
6916
6917           if (!options) {
6918             options = {};
6919           }
6920
6921           this.type = 'default';
6922           this.status = options.status === undefined ? 200 : options.status;
6923           this.ok = this.status >= 200 && this.status < 300;
6924           this.statusText = options.statusText === undefined ? '' : '' + options.statusText;
6925           this.headers = new Headers(options.headers);
6926           this.url = options.url || '';
6927
6928           this._initBody(bodyInit);
6929         }
6930         Body.call(Response.prototype);
6931
6932         Response.prototype.clone = function () {
6933           return new Response(this._bodyInit, {
6934             status: this.status,
6935             statusText: this.statusText,
6936             headers: new Headers(this.headers),
6937             url: this.url
6938           });
6939         };
6940
6941         Response.error = function () {
6942           var response = new Response(null, {
6943             status: 0,
6944             statusText: ''
6945           });
6946           response.type = 'error';
6947           return response;
6948         };
6949
6950         var redirectStatuses = [301, 302, 303, 307, 308];
6951
6952         Response.redirect = function (url, status) {
6953           if (redirectStatuses.indexOf(status) === -1) {
6954             throw new RangeError('Invalid status code');
6955           }
6956
6957           return new Response(null, {
6958             status: status,
6959             headers: {
6960               location: url
6961             }
6962           });
6963         };
6964
6965         var DOMException$2 = global$1.DOMException;
6966
6967         try {
6968           new DOMException$2();
6969         } catch (err) {
6970           DOMException$2 = function DOMException(message, name) {
6971             this.message = message;
6972             this.name = name;
6973             var error = Error(message);
6974             this.stack = error.stack;
6975           };
6976
6977           DOMException$2.prototype = Object.create(Error.prototype);
6978           DOMException$2.prototype.constructor = DOMException$2;
6979         }
6980
6981         function fetch$1(input, init) {
6982           return new Promise(function (resolve, reject) {
6983             var request = new Request(input, init);
6984
6985             if (request.signal && request.signal.aborted) {
6986               return reject(new DOMException$2('Aborted', 'AbortError'));
6987             }
6988
6989             var xhr = new XMLHttpRequest();
6990
6991             function abortXhr() {
6992               xhr.abort();
6993             }
6994
6995             xhr.onload = function () {
6996               var options = {
6997                 status: xhr.status,
6998                 statusText: xhr.statusText,
6999                 headers: parseHeaders(xhr.getAllResponseHeaders() || '')
7000               };
7001               options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
7002               var body = 'response' in xhr ? xhr.response : xhr.responseText;
7003               setTimeout(function () {
7004                 resolve(new Response(body, options));
7005               }, 0);
7006             };
7007
7008             xhr.onerror = function () {
7009               setTimeout(function () {
7010                 reject(new TypeError('Network request failed'));
7011               }, 0);
7012             };
7013
7014             xhr.ontimeout = function () {
7015               setTimeout(function () {
7016                 reject(new TypeError('Network request failed'));
7017               }, 0);
7018             };
7019
7020             xhr.onabort = function () {
7021               setTimeout(function () {
7022                 reject(new DOMException$2('Aborted', 'AbortError'));
7023               }, 0);
7024             };
7025
7026             function fixUrl(url) {
7027               try {
7028                 return url === '' && global$1.location.href ? global$1.location.href : url;
7029               } catch (e) {
7030                 return url;
7031               }
7032             }
7033
7034             xhr.open(request.method, fixUrl(request.url), true);
7035
7036             if (request.credentials === 'include') {
7037               xhr.withCredentials = true;
7038             } else if (request.credentials === 'omit') {
7039               xhr.withCredentials = false;
7040             }
7041
7042             if ('responseType' in xhr) {
7043               if (support.blob) {
7044                 xhr.responseType = 'blob';
7045               } else if (support.arrayBuffer && request.headers.get('Content-Type') && request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1) {
7046                 xhr.responseType = 'arraybuffer';
7047               }
7048             }
7049
7050             if (init && _typeof(init.headers) === 'object' && !(init.headers instanceof Headers)) {
7051               Object.getOwnPropertyNames(init.headers).forEach(function (name) {
7052                 xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
7053               });
7054             } else {
7055               request.headers.forEach(function (value, name) {
7056                 xhr.setRequestHeader(name, value);
7057               });
7058             }
7059
7060             if (request.signal) {
7061               request.signal.addEventListener('abort', abortXhr);
7062
7063               xhr.onreadystatechange = function () {
7064                 // DONE (success or failure)
7065                 if (xhr.readyState === 4) {
7066                   request.signal.removeEventListener('abort', abortXhr);
7067                 }
7068               };
7069             }
7070
7071             xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
7072           });
7073         }
7074         fetch$1.polyfill = true;
7075
7076         if (!global$1.fetch) {
7077           global$1.fetch = fetch$1;
7078           global$1.Headers = Headers;
7079           global$1.Request = Request;
7080           global$1.Response = Response;
7081         }
7082
7083         // `Object.defineProperty` method
7084         // https://tc39.es/ecma262/#sec-object.defineproperty
7085         _export({ target: 'Object', stat: true, forced: !descriptors, sham: !descriptors }, {
7086           defineProperty: objectDefineProperty.f
7087         });
7088
7089         // `Object.setPrototypeOf` method
7090         // https://tc39.es/ecma262/#sec-object.setprototypeof
7091         _export({ target: 'Object', stat: true }, {
7092           setPrototypeOf: objectSetPrototypeOf
7093         });
7094
7095         var FAILS_ON_PRIMITIVES$3 = fails(function () { objectGetPrototypeOf(1); });
7096
7097         // `Object.getPrototypeOf` method
7098         // https://tc39.es/ecma262/#sec-object.getprototypeof
7099         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$3, sham: !correctPrototypeGetter }, {
7100           getPrototypeOf: function getPrototypeOf(it) {
7101             return objectGetPrototypeOf(toObject(it));
7102           }
7103         });
7104
7105         var slice$2 = [].slice;
7106         var factories = {};
7107
7108         var construct = function (C, argsLength, args) {
7109           if (!(argsLength in factories)) {
7110             for (var list = [], i = 0; i < argsLength; i++) list[i] = 'a[' + i + ']';
7111             // eslint-disable-next-line no-new-func -- we have no proper alternatives, IE8- only
7112             factories[argsLength] = Function('C,a', 'return new C(' + list.join(',') + ')');
7113           } return factories[argsLength](C, args);
7114         };
7115
7116         // `Function.prototype.bind` method implementation
7117         // https://tc39.es/ecma262/#sec-function.prototype.bind
7118         var functionBind = Function.bind || function bind(that /* , ...args */) {
7119           var fn = aFunction(this);
7120           var partArgs = slice$2.call(arguments, 1);
7121           var boundFunction = function bound(/* args... */) {
7122             var args = partArgs.concat(slice$2.call(arguments));
7123             return this instanceof boundFunction ? construct(fn, args.length, args) : fn.apply(that, args);
7124           };
7125           if (isObject$4(fn.prototype)) boundFunction.prototype = fn.prototype;
7126           return boundFunction;
7127         };
7128
7129         var nativeConstruct = getBuiltIn('Reflect', 'construct');
7130
7131         // `Reflect.construct` method
7132         // https://tc39.es/ecma262/#sec-reflect.construct
7133         // MS Edge supports only 2 arguments and argumentsList argument is optional
7134         // FF Nightly sets third argument as `new.target`, but does not create `this` from it
7135         var NEW_TARGET_BUG = fails(function () {
7136           function F() { /* empty */ }
7137           return !(nativeConstruct(function () { /* empty */ }, [], F) instanceof F);
7138         });
7139         var ARGS_BUG = !fails(function () {
7140           nativeConstruct(function () { /* empty */ });
7141         });
7142         var FORCED$a = NEW_TARGET_BUG || ARGS_BUG;
7143
7144         _export({ target: 'Reflect', stat: true, forced: FORCED$a, sham: FORCED$a }, {
7145           construct: function construct(Target, args /* , newTarget */) {
7146             aFunction(Target);
7147             anObject(args);
7148             var newTarget = arguments.length < 3 ? Target : aFunction(arguments[2]);
7149             if (ARGS_BUG && !NEW_TARGET_BUG) return nativeConstruct(Target, args, newTarget);
7150             if (Target == newTarget) {
7151               // w/o altered newTarget, optimization for 0-4 arguments
7152               switch (args.length) {
7153                 case 0: return new Target();
7154                 case 1: return new Target(args[0]);
7155                 case 2: return new Target(args[0], args[1]);
7156                 case 3: return new Target(args[0], args[1], args[2]);
7157                 case 4: return new Target(args[0], args[1], args[2], args[3]);
7158               }
7159               // w/o altered newTarget, lot of arguments case
7160               var $args = [null];
7161               $args.push.apply($args, args);
7162               return new (functionBind.apply(Target, $args))();
7163             }
7164             // with altered newTarget, not support built-in constructors
7165             var proto = newTarget.prototype;
7166             var instance = objectCreate(isObject$4(proto) ? proto : Object.prototype);
7167             var result = Function.apply.call(Target, instance, args);
7168             return isObject$4(result) ? result : instance;
7169           }
7170         });
7171
7172         // `Reflect.get` method
7173         // https://tc39.es/ecma262/#sec-reflect.get
7174         function get$3(target, propertyKey /* , receiver */) {
7175           var receiver = arguments.length < 3 ? target : arguments[2];
7176           var descriptor, prototype;
7177           if (anObject(target) === receiver) return target[propertyKey];
7178           if (descriptor = objectGetOwnPropertyDescriptor.f(target, propertyKey)) return has$1(descriptor, 'value')
7179             ? descriptor.value
7180             : descriptor.get === undefined
7181               ? undefined
7182               : descriptor.get.call(receiver);
7183           if (isObject$4(prototype = objectGetPrototypeOf(target))) return get$3(prototype, propertyKey, receiver);
7184         }
7185
7186         _export({ target: 'Reflect', stat: true }, {
7187           get: get$3
7188         });
7189
7190         var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
7191
7192
7193         var FAILS_ON_PRIMITIVES$2 = fails(function () { nativeGetOwnPropertyDescriptor(1); });
7194         var FORCED$9 = !descriptors || FAILS_ON_PRIMITIVES$2;
7195
7196         // `Object.getOwnPropertyDescriptor` method
7197         // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
7198         _export({ target: 'Object', stat: true, forced: FORCED$9, sham: !descriptors }, {
7199           getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
7200             return nativeGetOwnPropertyDescriptor(toIndexedObject(it), key);
7201           }
7202         });
7203
7204         var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('splice');
7205
7206         var max$1 = Math.max;
7207         var min$3 = Math.min;
7208         var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
7209         var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded';
7210
7211         // `Array.prototype.splice` method
7212         // https://tc39.es/ecma262/#sec-array.prototype.splice
7213         // with adding support of @@species
7214         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 }, {
7215           splice: function splice(start, deleteCount /* , ...items */) {
7216             var O = toObject(this);
7217             var len = toLength(O.length);
7218             var actualStart = toAbsoluteIndex(start, len);
7219             var argumentsLength = arguments.length;
7220             var insertCount, actualDeleteCount, A, k, from, to;
7221             if (argumentsLength === 0) {
7222               insertCount = actualDeleteCount = 0;
7223             } else if (argumentsLength === 1) {
7224               insertCount = 0;
7225               actualDeleteCount = len - actualStart;
7226             } else {
7227               insertCount = argumentsLength - 2;
7228               actualDeleteCount = min$3(max$1(toInteger(deleteCount), 0), len - actualStart);
7229             }
7230             if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER$1) {
7231               throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
7232             }
7233             A = arraySpeciesCreate(O, actualDeleteCount);
7234             for (k = 0; k < actualDeleteCount; k++) {
7235               from = actualStart + k;
7236               if (from in O) createProperty(A, k, O[from]);
7237             }
7238             A.length = actualDeleteCount;
7239             if (insertCount < actualDeleteCount) {
7240               for (k = actualStart; k < len - actualDeleteCount; k++) {
7241                 from = k + actualDeleteCount;
7242                 to = k + insertCount;
7243                 if (from in O) O[to] = O[from];
7244                 else delete O[to];
7245               }
7246               for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
7247             } else if (insertCount > actualDeleteCount) {
7248               for (k = len - actualDeleteCount; k > actualStart; k--) {
7249                 from = k + actualDeleteCount - 1;
7250                 to = k + insertCount - 1;
7251                 if (from in O) O[to] = O[from];
7252                 else delete O[to];
7253               }
7254             }
7255             for (k = 0; k < insertCount; k++) {
7256               O[k + actualStart] = arguments[k + 2];
7257             }
7258             O.length = len - actualDeleteCount + insertCount;
7259             return A;
7260           }
7261         });
7262
7263         // `Symbol.toStringTag` well-known symbol
7264         // https://tc39.es/ecma262/#sec-symbol.tostringtag
7265         defineWellKnownSymbol('toStringTag');
7266
7267         // JSON[@@toStringTag] property
7268         // https://tc39.es/ecma262/#sec-json-@@tostringtag
7269         setToStringTag(global$2.JSON, 'JSON', true);
7270
7271         // Math[@@toStringTag] property
7272         // https://tc39.es/ecma262/#sec-math-@@tostringtag
7273         setToStringTag(Math, 'Math', true);
7274
7275         (function (factory) {
7276           factory();
7277         })(function () {
7278
7279           function _classCallCheck(instance, Constructor) {
7280             if (!(instance instanceof Constructor)) {
7281               throw new TypeError("Cannot call a class as a function");
7282             }
7283           }
7284
7285           function _defineProperties(target, props) {
7286             for (var i = 0; i < props.length; i++) {
7287               var descriptor = props[i];
7288               descriptor.enumerable = descriptor.enumerable || false;
7289               descriptor.configurable = true;
7290               if ("value" in descriptor) descriptor.writable = true;
7291               Object.defineProperty(target, descriptor.key, descriptor);
7292             }
7293           }
7294
7295           function _createClass(Constructor, protoProps, staticProps) {
7296             if (protoProps) _defineProperties(Constructor.prototype, protoProps);
7297             if (staticProps) _defineProperties(Constructor, staticProps);
7298             return Constructor;
7299           }
7300
7301           function _inherits(subClass, superClass) {
7302             if (typeof superClass !== "function" && superClass !== null) {
7303               throw new TypeError("Super expression must either be null or a function");
7304             }
7305
7306             subClass.prototype = Object.create(superClass && superClass.prototype, {
7307               constructor: {
7308                 value: subClass,
7309                 writable: true,
7310                 configurable: true
7311               }
7312             });
7313             if (superClass) _setPrototypeOf(subClass, superClass);
7314           }
7315
7316           function _getPrototypeOf(o) {
7317             _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
7318               return o.__proto__ || Object.getPrototypeOf(o);
7319             };
7320             return _getPrototypeOf(o);
7321           }
7322
7323           function _setPrototypeOf(o, p) {
7324             _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
7325               o.__proto__ = p;
7326               return o;
7327             };
7328
7329             return _setPrototypeOf(o, p);
7330           }
7331
7332           function _isNativeReflectConstruct() {
7333             if (typeof Reflect === "undefined" || !Reflect.construct) return false;
7334             if (Reflect.construct.sham) return false;
7335             if (typeof Proxy === "function") return true;
7336
7337             try {
7338               Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
7339               return true;
7340             } catch (e) {
7341               return false;
7342             }
7343           }
7344
7345           function _assertThisInitialized(self) {
7346             if (self === void 0) {
7347               throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
7348             }
7349
7350             return self;
7351           }
7352
7353           function _possibleConstructorReturn(self, call) {
7354             if (call && (_typeof(call) === "object" || typeof call === "function")) {
7355               return call;
7356             }
7357
7358             return _assertThisInitialized(self);
7359           }
7360
7361           function _createSuper(Derived) {
7362             var hasNativeReflectConstruct = _isNativeReflectConstruct();
7363
7364             return function _createSuperInternal() {
7365               var Super = _getPrototypeOf(Derived),
7366                   result;
7367
7368               if (hasNativeReflectConstruct) {
7369                 var NewTarget = _getPrototypeOf(this).constructor;
7370
7371                 result = Reflect.construct(Super, arguments, NewTarget);
7372               } else {
7373                 result = Super.apply(this, arguments);
7374               }
7375
7376               return _possibleConstructorReturn(this, result);
7377             };
7378           }
7379
7380           function _superPropBase(object, property) {
7381             while (!Object.prototype.hasOwnProperty.call(object, property)) {
7382               object = _getPrototypeOf(object);
7383               if (object === null) break;
7384             }
7385
7386             return object;
7387           }
7388
7389           function _get(target, property, receiver) {
7390             if (typeof Reflect !== "undefined" && Reflect.get) {
7391               _get = Reflect.get;
7392             } else {
7393               _get = function _get(target, property, receiver) {
7394                 var base = _superPropBase(target, property);
7395
7396                 if (!base) return;
7397                 var desc = Object.getOwnPropertyDescriptor(base, property);
7398
7399                 if (desc.get) {
7400                   return desc.get.call(receiver);
7401                 }
7402
7403                 return desc.value;
7404               };
7405             }
7406
7407             return _get(target, property, receiver || target);
7408           }
7409
7410           var Emitter = /*#__PURE__*/function () {
7411             function Emitter() {
7412               _classCallCheck(this, Emitter);
7413
7414               Object.defineProperty(this, 'listeners', {
7415                 value: {},
7416                 writable: true,
7417                 configurable: true
7418               });
7419             }
7420
7421             _createClass(Emitter, [{
7422               key: "addEventListener",
7423               value: function addEventListener(type, callback, options) {
7424                 if (!(type in this.listeners)) {
7425                   this.listeners[type] = [];
7426                 }
7427
7428                 this.listeners[type].push({
7429                   callback: callback,
7430                   options: options
7431                 });
7432               }
7433             }, {
7434               key: "removeEventListener",
7435               value: function removeEventListener(type, callback) {
7436                 if (!(type in this.listeners)) {
7437                   return;
7438                 }
7439
7440                 var stack = this.listeners[type];
7441
7442                 for (var i = 0, l = stack.length; i < l; i++) {
7443                   if (stack[i].callback === callback) {
7444                     stack.splice(i, 1);
7445                     return;
7446                   }
7447                 }
7448               }
7449             }, {
7450               key: "dispatchEvent",
7451               value: function dispatchEvent(event) {
7452                 if (!(event.type in this.listeners)) {
7453                   return;
7454                 }
7455
7456                 var stack = this.listeners[event.type];
7457                 var stackToCall = stack.slice();
7458
7459                 for (var i = 0, l = stackToCall.length; i < l; i++) {
7460                   var listener = stackToCall[i];
7461
7462                   try {
7463                     listener.callback.call(this, event);
7464                   } catch (e) {
7465                     Promise.resolve().then(function () {
7466                       throw e;
7467                     });
7468                   }
7469
7470                   if (listener.options && listener.options.once) {
7471                     this.removeEventListener(event.type, listener.callback);
7472                   }
7473                 }
7474
7475                 return !event.defaultPrevented;
7476               }
7477             }]);
7478
7479             return Emitter;
7480           }();
7481
7482           var AbortSignal = /*#__PURE__*/function (_Emitter) {
7483             _inherits(AbortSignal, _Emitter);
7484
7485             var _super = _createSuper(AbortSignal);
7486
7487             function AbortSignal() {
7488               var _this;
7489
7490               _classCallCheck(this, AbortSignal);
7491
7492               _this = _super.call(this); // Some versions of babel does not transpile super() correctly for IE <= 10, if the parent
7493               // constructor has failed to run, then "this.listeners" will still be undefined and then we call
7494               // the parent constructor directly instead as a workaround. For general details, see babel bug:
7495               // https://github.com/babel/babel/issues/3041
7496               // This hack was added as a fix for the issue described here:
7497               // https://github.com/Financial-Times/polyfill-library/pull/59#issuecomment-477558042
7498
7499               if (!_this.listeners) {
7500                 Emitter.call(_assertThisInitialized(_this));
7501               } // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
7502               // we want Object.keys(new AbortController().signal) to be [] for compat with the native impl
7503
7504
7505               Object.defineProperty(_assertThisInitialized(_this), 'aborted', {
7506                 value: false,
7507                 writable: true,
7508                 configurable: true
7509               });
7510               Object.defineProperty(_assertThisInitialized(_this), 'onabort', {
7511                 value: null,
7512                 writable: true,
7513                 configurable: true
7514               });
7515               return _this;
7516             }
7517
7518             _createClass(AbortSignal, [{
7519               key: "toString",
7520               value: function toString() {
7521                 return '[object AbortSignal]';
7522               }
7523             }, {
7524               key: "dispatchEvent",
7525               value: function dispatchEvent(event) {
7526                 if (event.type === 'abort') {
7527                   this.aborted = true;
7528
7529                   if (typeof this.onabort === 'function') {
7530                     this.onabort.call(this, event);
7531                   }
7532                 }
7533
7534                 _get(_getPrototypeOf(AbortSignal.prototype), "dispatchEvent", this).call(this, event);
7535               }
7536             }]);
7537
7538             return AbortSignal;
7539           }(Emitter);
7540
7541           var AbortController = /*#__PURE__*/function () {
7542             function AbortController() {
7543               _classCallCheck(this, AbortController); // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
7544               // we want Object.keys(new AbortController()) to be [] for compat with the native impl
7545
7546
7547               Object.defineProperty(this, 'signal', {
7548                 value: new AbortSignal(),
7549                 writable: true,
7550                 configurable: true
7551               });
7552             }
7553
7554             _createClass(AbortController, [{
7555               key: "abort",
7556               value: function abort() {
7557                 var event;
7558
7559                 try {
7560                   event = new Event('abort');
7561                 } catch (e) {
7562                   if (typeof document !== 'undefined') {
7563                     if (!document.createEvent) {
7564                       // For Internet Explorer 8:
7565                       event = document.createEventObject();
7566                       event.type = 'abort';
7567                     } else {
7568                       // For Internet Explorer 11:
7569                       event = document.createEvent('Event');
7570                       event.initEvent('abort', false, false);
7571                     }
7572                   } else {
7573                     // Fallback where document isn't available:
7574                     event = {
7575                       type: 'abort',
7576                       bubbles: false,
7577                       cancelable: false
7578                     };
7579                   }
7580                 }
7581
7582                 this.signal.dispatchEvent(event);
7583               }
7584             }, {
7585               key: "toString",
7586               value: function toString() {
7587                 return '[object AbortController]';
7588               }
7589             }]);
7590
7591             return AbortController;
7592           }();
7593
7594           if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
7595             // These are necessary to make sure that we get correct output for:
7596             // Object.prototype.toString.call(new AbortController())
7597             AbortController.prototype[Symbol.toStringTag] = 'AbortController';
7598             AbortSignal.prototype[Symbol.toStringTag] = 'AbortSignal';
7599           }
7600
7601           function polyfillNeeded(self) {
7602             if (self.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
7603               console.log('__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL=true is set, will force install polyfill');
7604               return true;
7605             } // Note that the "unfetch" minimal fetch polyfill defines fetch() without
7606             // defining window.Request, and this polyfill need to work on top of unfetch
7607             // so the below feature detection needs the !self.AbortController part.
7608             // The Request.prototype check is also needed because Safari versions 11.1.2
7609             // up to and including 12.1.x has a window.AbortController present but still
7610             // does NOT correctly implement abortable fetch:
7611             // https://bugs.webkit.org/show_bug.cgi?id=174980#c2
7612
7613
7614             return typeof self.Request === 'function' && !self.Request.prototype.hasOwnProperty('signal') || !self.AbortController;
7615           }
7616           /**
7617            * Note: the "fetch.Request" default value is available for fetch imported from
7618            * the "node-fetch" package and not in browsers. This is OK since browsers
7619            * will be importing umd-polyfill.js from that path "self" is passed the
7620            * decorator so the default value will not be used (because browsers that define
7621            * fetch also has Request). One quirky setup where self.fetch exists but
7622            * self.Request does not is when the "unfetch" minimal fetch polyfill is used
7623            * on top of IE11; for this case the browser will try to use the fetch.Request
7624            * default value which in turn will be undefined but then then "if (Request)"
7625            * will ensure that you get a patched fetch but still no Request (as expected).
7626            * @param {fetch, Request = fetch.Request}
7627            * @returns {fetch: abortableFetch, Request: AbortableRequest}
7628            */
7629
7630
7631           function abortableFetchDecorator(patchTargets) {
7632             if ('function' === typeof patchTargets) {
7633               patchTargets = {
7634                 fetch: patchTargets
7635               };
7636             }
7637
7638             var _patchTargets = patchTargets,
7639                 fetch = _patchTargets.fetch,
7640                 _patchTargets$Request = _patchTargets.Request,
7641                 NativeRequest = _patchTargets$Request === void 0 ? fetch.Request : _patchTargets$Request,
7642                 NativeAbortController = _patchTargets.AbortController,
7643                 _patchTargets$__FORCE = _patchTargets.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL,
7644                 __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL = _patchTargets$__FORCE === void 0 ? false : _patchTargets$__FORCE;
7645
7646             if (!polyfillNeeded({
7647               fetch: fetch,
7648               Request: NativeRequest,
7649               AbortController: NativeAbortController,
7650               __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL: __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL
7651             })) {
7652               return {
7653                 fetch: fetch,
7654                 Request: Request
7655               };
7656             }
7657
7658             var Request = NativeRequest; // Note that the "unfetch" minimal fetch polyfill defines fetch() without
7659             // defining window.Request, and this polyfill need to work on top of unfetch
7660             // hence we only patch it if it's available. Also we don't patch it if signal
7661             // is already available on the Request prototype because in this case support
7662             // is present and the patching below can cause a crash since it assigns to
7663             // request.signal which is technically a read-only property. This latter error
7664             // happens when you run the main5.js node-fetch example in the repo
7665             // "abortcontroller-polyfill-examples". The exact error is:
7666             //   request.signal = init.signal;
7667             //   ^
7668             // TypeError: Cannot set property signal of #<Request> which has only a getter
7669
7670             if (Request && !Request.prototype.hasOwnProperty('signal') || __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
7671               Request = function Request(input, init) {
7672                 var signal;
7673
7674                 if (init && init.signal) {
7675                   signal = init.signal; // Never pass init.signal to the native Request implementation when the polyfill has
7676                   // been installed because if we're running on top of a browser with a
7677                   // working native AbortController (i.e. the polyfill was installed due to
7678                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
7679                   // fake AbortSignal to the native fetch will trigger:
7680                   // TypeError: Failed to construct 'Request': member signal is not of type AbortSignal.
7681
7682                   delete init.signal;
7683                 }
7684
7685                 var request = new NativeRequest(input, init);
7686
7687                 if (signal) {
7688                   Object.defineProperty(request, 'signal', {
7689                     writable: false,
7690                     enumerable: false,
7691                     configurable: true,
7692                     value: signal
7693                   });
7694                 }
7695
7696                 return request;
7697               };
7698
7699               Request.prototype = NativeRequest.prototype;
7700             }
7701
7702             var realFetch = fetch;
7703
7704             var abortableFetch = function abortableFetch(input, init) {
7705               var signal = Request && Request.prototype.isPrototypeOf(input) ? input.signal : init ? init.signal : undefined;
7706
7707               if (signal) {
7708                 var abortError;
7709
7710                 try {
7711                   abortError = new DOMException('Aborted', 'AbortError');
7712                 } catch (err) {
7713                   // IE 11 does not support calling the DOMException constructor, use a
7714                   // regular error object on it instead.
7715                   abortError = new Error('Aborted');
7716                   abortError.name = 'AbortError';
7717                 } // Return early if already aborted, thus avoiding making an HTTP request
7718
7719
7720                 if (signal.aborted) {
7721                   return Promise.reject(abortError);
7722                 } // Turn an event into a promise, reject it once `abort` is dispatched
7723
7724
7725                 var cancellation = new Promise(function (_, reject) {
7726                   signal.addEventListener('abort', function () {
7727                     return reject(abortError);
7728                   }, {
7729                     once: true
7730                   });
7731                 });
7732
7733                 if (init && init.signal) {
7734                   // Never pass .signal to the native implementation when the polyfill has
7735                   // been installed because if we're running on top of a browser with a
7736                   // working native AbortController (i.e. the polyfill was installed due to
7737                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
7738                   // fake AbortSignal to the native fetch will trigger:
7739                   // TypeError: Failed to execute 'fetch' on 'Window': member signal is not of type AbortSignal.
7740                   delete init.signal;
7741                 } // Return the fastest promise (don't need to wait for request to finish)
7742
7743
7744                 return Promise.race([cancellation, realFetch(input, init)]);
7745               }
7746
7747               return realFetch(input, init);
7748             };
7749
7750             return {
7751               fetch: abortableFetch,
7752               Request: Request
7753             };
7754           }
7755
7756           (function (self) {
7757             if (!polyfillNeeded(self)) {
7758               return;
7759             }
7760
7761             if (!self.fetch) {
7762               console.warn('fetch() is not available, cannot install abortcontroller-polyfill');
7763               return;
7764             }
7765
7766             var _abortableFetch = abortableFetchDecorator(self),
7767                 fetch = _abortableFetch.fetch,
7768                 Request = _abortableFetch.Request;
7769
7770             self.fetch = fetch;
7771             self.Request = Request;
7772             Object.defineProperty(self, 'AbortController', {
7773               writable: true,
7774               enumerable: false,
7775               configurable: true,
7776               value: AbortController
7777             });
7778             Object.defineProperty(self, 'AbortSignal', {
7779               writable: true,
7780               enumerable: false,
7781               configurable: true,
7782               value: AbortSignal
7783             });
7784           })(typeof self !== 'undefined' ? self : commonjsGlobal);
7785         });
7786
7787         function actionAddEntity(way) {
7788           return function (graph) {
7789             return graph.replace(way);
7790           };
7791         }
7792
7793         var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
7794         var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
7795         var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';
7796
7797         // We can't use this feature detection in V8 since it causes
7798         // deoptimization and serious performance degradation
7799         // https://github.com/zloirock/core-js/issues/679
7800         var IS_CONCAT_SPREADABLE_SUPPORT = engineV8Version >= 51 || !fails(function () {
7801           var array = [];
7802           array[IS_CONCAT_SPREADABLE] = false;
7803           return array.concat()[0] !== array;
7804         });
7805
7806         var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');
7807
7808         var isConcatSpreadable = function (O) {
7809           if (!isObject$4(O)) return false;
7810           var spreadable = O[IS_CONCAT_SPREADABLE];
7811           return spreadable !== undefined ? !!spreadable : isArray(O);
7812         };
7813
7814         var FORCED$8 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;
7815
7816         // `Array.prototype.concat` method
7817         // https://tc39.es/ecma262/#sec-array.prototype.concat
7818         // with adding support of @@isConcatSpreadable and @@species
7819         _export({ target: 'Array', proto: true, forced: FORCED$8 }, {
7820           // eslint-disable-next-line no-unused-vars -- required for `.length`
7821           concat: function concat(arg) {
7822             var O = toObject(this);
7823             var A = arraySpeciesCreate(O, 0);
7824             var n = 0;
7825             var i, k, length, len, E;
7826             for (i = -1, length = arguments.length; i < length; i++) {
7827               E = i === -1 ? O : arguments[i];
7828               if (isConcatSpreadable(E)) {
7829                 len = toLength(E.length);
7830                 if (n + len > MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
7831                 for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
7832               } else {
7833                 if (n >= MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
7834                 createProperty(A, n++, E);
7835               }
7836             }
7837             A.length = n;
7838             return A;
7839           }
7840         });
7841
7842         // `Object.assign` method
7843         // https://tc39.es/ecma262/#sec-object.assign
7844         // eslint-disable-next-line es/no-object-assign -- required for testing
7845         _export({ target: 'Object', stat: true, forced: Object.assign !== objectAssign }, {
7846           assign: objectAssign
7847         });
7848
7849         var $filter = arrayIteration.filter;
7850
7851
7852         var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('filter');
7853
7854         // `Array.prototype.filter` method
7855         // https://tc39.es/ecma262/#sec-array.prototype.filter
7856         // with adding support of @@species
7857         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT }, {
7858           filter: function filter(callbackfn /* , thisArg */) {
7859             return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
7860           }
7861         });
7862
7863         var FAILS_ON_PRIMITIVES$1 = fails(function () { objectKeys(1); });
7864
7865         // `Object.keys` method
7866         // https://tc39.es/ecma262/#sec-object.keys
7867         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$1 }, {
7868           keys: function keys(it) {
7869             return objectKeys(toObject(it));
7870           }
7871         });
7872
7873         var nativeReverse = [].reverse;
7874         var test$1 = [1, 2];
7875
7876         // `Array.prototype.reverse` method
7877         // https://tc39.es/ecma262/#sec-array.prototype.reverse
7878         // fix for Safari 12.0 bug
7879         // https://bugs.webkit.org/show_bug.cgi?id=188794
7880         _export({ target: 'Array', proto: true, forced: String(test$1) === String(test$1.reverse()) }, {
7881           reverse: function reverse() {
7882             // eslint-disable-next-line no-self-assign -- dirty hack
7883             if (isArray(this)) this.length = this.length;
7884             return nativeReverse.call(this);
7885           }
7886         });
7887
7888         var trim$4 = stringTrim.trim;
7889
7890
7891         var $parseFloat = global$2.parseFloat;
7892         var FORCED$7 = 1 / $parseFloat(whitespaces + '-0') !== -Infinity;
7893
7894         // `parseFloat` method
7895         // https://tc39.es/ecma262/#sec-parsefloat-string
7896         var numberParseFloat = FORCED$7 ? function parseFloat(string) {
7897           var trimmedString = trim$4(String(string));
7898           var result = $parseFloat(trimmedString);
7899           return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
7900         } : $parseFloat;
7901
7902         // `parseFloat` method
7903         // https://tc39.es/ecma262/#sec-parsefloat-string
7904         _export({ global: true, forced: parseFloat != numberParseFloat }, {
7905           parseFloat: numberParseFloat
7906         });
7907
7908         /*
7909         Order the nodes of a way in reverse order and reverse any direction dependent tags
7910         other than `oneway`. (We assume that correcting a backwards oneway is the primary
7911         reason for reversing a way.)
7912
7913         In addition, numeric-valued `incline` tags are negated.
7914
7915         The JOSM implementation was used as a guide, but transformations that were of unclear benefit
7916         or adjusted tags that don't seem to be used in practice were omitted.
7917
7918         References:
7919             http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
7920             http://wiki.openstreetmap.org/wiki/Key:direction#Steps
7921             http://wiki.openstreetmap.org/wiki/Key:incline
7922             http://wiki.openstreetmap.org/wiki/Route#Members
7923             http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
7924             http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
7925             http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
7926         */
7927         function actionReverse(entityID, options) {
7928           var ignoreKey = /^.*(_|:)?(description|name|note|website|ref|source|comment|watch|attribution)(_|:)?/;
7929           var numeric = /^([+\-]?)(?=[\d.])/;
7930           var directionKey = /direction$/;
7931           var turn_lanes = /^turn:lanes:?/;
7932           var keyReplacements = [[/:right$/, ':left'], [/:left$/, ':right'], [/:forward$/, ':backward'], [/:backward$/, ':forward'], [/:right:/, ':left:'], [/:left:/, ':right:'], [/:forward:/, ':backward:'], [/:backward:/, ':forward:']];
7933           var valueReplacements = {
7934             left: 'right',
7935             right: 'left',
7936             up: 'down',
7937             down: 'up',
7938             forward: 'backward',
7939             backward: 'forward',
7940             forwards: 'backward',
7941             backwards: 'forward'
7942           };
7943           var roleReplacements = {
7944             forward: 'backward',
7945             backward: 'forward',
7946             forwards: 'backward',
7947             backwards: 'forward'
7948           };
7949           var onewayReplacements = {
7950             yes: '-1',
7951             '1': '-1',
7952             '-1': 'yes'
7953           };
7954           var compassReplacements = {
7955             N: 'S',
7956             NNE: 'SSW',
7957             NE: 'SW',
7958             ENE: 'WSW',
7959             E: 'W',
7960             ESE: 'WNW',
7961             SE: 'NW',
7962             SSE: 'NNW',
7963             S: 'N',
7964             SSW: 'NNE',
7965             SW: 'NE',
7966             WSW: 'ENE',
7967             W: 'E',
7968             WNW: 'ESE',
7969             NW: 'SE',
7970             NNW: 'SSE'
7971           };
7972
7973           function reverseKey(key) {
7974             for (var i = 0; i < keyReplacements.length; ++i) {
7975               var replacement = keyReplacements[i];
7976
7977               if (replacement[0].test(key)) {
7978                 return key.replace(replacement[0], replacement[1]);
7979               }
7980             }
7981
7982             return key;
7983           }
7984
7985           function reverseValue(key, value, includeAbsolute) {
7986             if (ignoreKey.test(key)) return value; // Turn lanes are left/right to key (not way) direction - #5674
7987
7988             if (turn_lanes.test(key)) {
7989               return value;
7990             } else if (key === 'incline' && numeric.test(value)) {
7991               return value.replace(numeric, function (_, sign) {
7992                 return sign === '-' ? '' : '-';
7993               });
7994             } else if (options && options.reverseOneway && key === 'oneway') {
7995               return onewayReplacements[value] || value;
7996             } else if (includeAbsolute && directionKey.test(key)) {
7997               if (compassReplacements[value]) return compassReplacements[value];
7998               var degrees = parseFloat(value);
7999
8000               if (typeof degrees === 'number' && !isNaN(degrees)) {
8001                 if (degrees < 180) {
8002                   degrees += 180;
8003                 } else {
8004                   degrees -= 180;
8005                 }
8006
8007                 return degrees.toString();
8008               }
8009             }
8010
8011             return valueReplacements[value] || value;
8012           } // Reverse the direction of tags attached to the nodes - #3076
8013
8014
8015           function reverseNodeTags(graph, nodeIDs) {
8016             for (var i = 0; i < nodeIDs.length; i++) {
8017               var node = graph.hasEntity(nodeIDs[i]);
8018               if (!node || !Object.keys(node.tags).length) continue;
8019               var tags = {};
8020
8021               for (var key in node.tags) {
8022                 tags[reverseKey(key)] = reverseValue(key, node.tags[key], node.id === entityID);
8023               }
8024
8025               graph = graph.replace(node.update({
8026                 tags: tags
8027               }));
8028             }
8029
8030             return graph;
8031           }
8032
8033           function reverseWay(graph, way) {
8034             var nodes = way.nodes.slice().reverse();
8035             var tags = {};
8036             var role;
8037
8038             for (var key in way.tags) {
8039               tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
8040             }
8041
8042             graph.parentRelations(way).forEach(function (relation) {
8043               relation.members.forEach(function (member, index) {
8044                 if (member.id === way.id && (role = roleReplacements[member.role])) {
8045                   relation = relation.updateMember({
8046                     role: role
8047                   }, index);
8048                   graph = graph.replace(relation);
8049                 }
8050               });
8051             }); // Reverse any associated directions on nodes on the way and then replace
8052             // the way itself with the reversed node ids and updated way tags
8053
8054             return reverseNodeTags(graph, nodes).replace(way.update({
8055               nodes: nodes,
8056               tags: tags
8057             }));
8058           }
8059
8060           var action = function action(graph) {
8061             var entity = graph.entity(entityID);
8062
8063             if (entity.type === 'way') {
8064               return reverseWay(graph, entity);
8065             }
8066
8067             return reverseNodeTags(graph, [entityID]);
8068           };
8069
8070           action.disabled = function (graph) {
8071             var entity = graph.hasEntity(entityID);
8072             if (!entity || entity.type === 'way') return false;
8073
8074             for (var key in entity.tags) {
8075               var value = entity.tags[key];
8076
8077               if (reverseKey(key) !== key || reverseValue(key, value, true) !== value) {
8078                 return false;
8079               }
8080             }
8081
8082             return 'nondirectional_node';
8083           };
8084
8085           action.entityID = function () {
8086             return entityID;
8087           };
8088
8089           return action;
8090         }
8091
8092         function osmIsInterestingTag(key) {
8093           return key !== 'attribution' && key !== 'created_by' && key !== 'source' && key !== 'odbl' && key.indexOf('source:') !== 0 && key.indexOf('source_ref') !== 0 && // purposely exclude colon
8094           key.indexOf('tiger:') !== 0;
8095         }
8096         var osmAreaKeys = {};
8097         function osmSetAreaKeys(value) {
8098           osmAreaKeys = value;
8099         } // returns an object with the tag from `tags` that implies an area geometry, if any
8100
8101         function osmTagSuggestingArea(tags) {
8102           if (tags.area === 'yes') return {
8103             area: 'yes'
8104           };
8105           if (tags.area === 'no') return null; // `highway` and `railway` are typically linear features, but there
8106           // are a few exceptions that should be treated as areas, even in the
8107           // absence of a proper `area=yes` or `areaKeys` tag.. see #4194
8108
8109           var lineKeys = {
8110             highway: {
8111               rest_area: true,
8112               services: true
8113             },
8114             railway: {
8115               roundhouse: true,
8116               station: true,
8117               traverser: true,
8118               turntable: true,
8119               wash: true
8120             }
8121           };
8122           var returnTags = {};
8123
8124           for (var key in tags) {
8125             if (key in osmAreaKeys && !(tags[key] in osmAreaKeys[key])) {
8126               returnTags[key] = tags[key];
8127               return returnTags;
8128             }
8129
8130             if (key in lineKeys && tags[key] in lineKeys[key]) {
8131               returnTags[key] = tags[key];
8132               return returnTags;
8133             }
8134           }
8135
8136           return null;
8137         } // Tags that indicate a node can be a standalone point
8138         // e.g. { amenity: { bar: true, parking: true, ... } ... }
8139
8140         var osmPointTags = {};
8141         function osmSetPointTags(value) {
8142           osmPointTags = value;
8143         } // Tags that indicate a node can be part of a way
8144         // e.g. { amenity: { parking: true, ... }, highway: { stop: true ... } ... }
8145
8146         var osmVertexTags = {};
8147         function osmSetVertexTags(value) {
8148           osmVertexTags = value;
8149         }
8150         function osmNodeGeometriesForTags(nodeTags) {
8151           var geometries = {};
8152
8153           for (var key in nodeTags) {
8154             if (osmPointTags[key] && (osmPointTags[key]['*'] || osmPointTags[key][nodeTags[key]])) {
8155               geometries.point = true;
8156             }
8157
8158             if (osmVertexTags[key] && (osmVertexTags[key]['*'] || osmVertexTags[key][nodeTags[key]])) {
8159               geometries.vertex = true;
8160             } // break early if both are already supported
8161
8162
8163             if (geometries.point && geometries.vertex) break;
8164           }
8165
8166           return geometries;
8167         }
8168         var osmOneWayTags = {
8169           'aerialway': {
8170             'chair_lift': true,
8171             'drag_lift': true,
8172             'j-bar': true,
8173             'magic_carpet': true,
8174             'mixed_lift': true,
8175             'platter': true,
8176             'rope_tow': true,
8177             't-bar': true,
8178             'zip_line': true
8179           },
8180           'highway': {
8181             'motorway': true
8182           },
8183           'junction': {
8184             'circular': true,
8185             'roundabout': true
8186           },
8187           'man_made': {
8188             'goods_conveyor': true,
8189             'piste:halfpipe': true
8190           },
8191           'piste:type': {
8192             'downhill': true,
8193             'sled': true,
8194             'yes': true
8195           },
8196           'waterway': {
8197             'canal': true,
8198             'ditch': true,
8199             'drain': true,
8200             'fish_pass': true,
8201             'river': true,
8202             'stream': true,
8203             'tidal_channel': true
8204           }
8205         }; // solid and smooth surfaces akin to the assumed default road surface in OSM
8206
8207         var osmPavedTags = {
8208           'surface': {
8209             'paved': true,
8210             'asphalt': true,
8211             'concrete': true,
8212             'concrete:lanes': true,
8213             'concrete:plates': true
8214           },
8215           'tracktype': {
8216             'grade1': true
8217           }
8218         }; // solid, if somewhat uncommon surfaces with a high range of smoothness
8219
8220         var osmSemipavedTags = {
8221           'surface': {
8222             'cobblestone': true,
8223             'cobblestone:flattened': true,
8224             'unhewn_cobblestone': true,
8225             'sett': true,
8226             'paving_stones': true,
8227             'metal': true,
8228             'wood': true
8229           }
8230         };
8231         var osmRightSideIsInsideTags = {
8232           'natural': {
8233             'cliff': true,
8234             'coastline': 'coastline'
8235           },
8236           'barrier': {
8237             'retaining_wall': true,
8238             'kerb': true,
8239             'guard_rail': true,
8240             'city_wall': true
8241           },
8242           'man_made': {
8243             'embankment': true
8244           },
8245           'waterway': {
8246             'weir': true
8247           }
8248         }; // "highway" tag values for pedestrian or vehicle right-of-ways that make up the routable network
8249         // (does not include `raceway`)
8250
8251         var osmRoutableHighwayTagValues = {
8252           motorway: true,
8253           trunk: true,
8254           primary: true,
8255           secondary: true,
8256           tertiary: true,
8257           residential: true,
8258           motorway_link: true,
8259           trunk_link: true,
8260           primary_link: true,
8261           secondary_link: true,
8262           tertiary_link: true,
8263           unclassified: true,
8264           road: true,
8265           service: true,
8266           track: true,
8267           living_street: true,
8268           bus_guideway: true,
8269           path: true,
8270           footway: true,
8271           cycleway: true,
8272           bridleway: true,
8273           pedestrian: true,
8274           corridor: true,
8275           steps: true
8276         }; // "highway" tag values that generally do not allow motor vehicles
8277
8278         var osmPathHighwayTagValues = {
8279           path: true,
8280           footway: true,
8281           cycleway: true,
8282           bridleway: true,
8283           pedestrian: true,
8284           corridor: true,
8285           steps: true
8286         }; // "railway" tag values representing existing railroad tracks (purposely does not include 'abandoned')
8287
8288         var osmRailwayTrackTagValues = {
8289           rail: true,
8290           light_rail: true,
8291           tram: true,
8292           subway: true,
8293           monorail: true,
8294           funicular: true,
8295           miniature: true,
8296           narrow_gauge: true,
8297           disused: true,
8298           preserved: true
8299         }; // "waterway" tag values for line features representing water flow
8300
8301         var osmFlowingWaterwayTagValues = {
8302           canal: true,
8303           ditch: true,
8304           drain: true,
8305           fish_pass: true,
8306           river: true,
8307           stream: true,
8308           tidal_channel: true
8309         };
8310
8311         var trim$3 = stringTrim.trim;
8312
8313
8314         var $parseInt = global$2.parseInt;
8315         var hex$2 = /^[+-]?0[Xx]/;
8316         var FORCED$6 = $parseInt(whitespaces + '08') !== 8 || $parseInt(whitespaces + '0x16') !== 22;
8317
8318         // `parseInt` method
8319         // https://tc39.es/ecma262/#sec-parseint-string-radix
8320         var numberParseInt = FORCED$6 ? function parseInt(string, radix) {
8321           var S = trim$3(String(string));
8322           return $parseInt(S, (radix >>> 0) || (hex$2.test(S) ? 16 : 10));
8323         } : $parseInt;
8324
8325         // `parseInt` method
8326         // https://tc39.es/ecma262/#sec-parseint-string-radix
8327         _export({ global: true, forced: parseInt != numberParseInt }, {
8328           parseInt: numberParseInt
8329         });
8330
8331         var freezing = !fails(function () {
8332           // eslint-disable-next-line es/no-object-isextensible, es/no-object-preventextensions -- required for testing
8333           return Object.isExtensible(Object.preventExtensions({}));
8334         });
8335
8336         var internalMetadata = createCommonjsModule(function (module) {
8337         var defineProperty = objectDefineProperty.f;
8338
8339
8340
8341         var METADATA = uid('meta');
8342         var id = 0;
8343
8344         // eslint-disable-next-line es/no-object-isextensible -- safe
8345         var isExtensible = Object.isExtensible || function () {
8346           return true;
8347         };
8348
8349         var setMetadata = function (it) {
8350           defineProperty(it, METADATA, { value: {
8351             objectID: 'O' + id++, // object ID
8352             weakData: {}          // weak collections IDs
8353           } });
8354         };
8355
8356         var fastKey = function (it, create) {
8357           // return a primitive with prefix
8358           if (!isObject$4(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
8359           if (!has$1(it, METADATA)) {
8360             // can't set metadata to uncaught frozen object
8361             if (!isExtensible(it)) return 'F';
8362             // not necessary to add metadata
8363             if (!create) return 'E';
8364             // add missing metadata
8365             setMetadata(it);
8366           // return object ID
8367           } return it[METADATA].objectID;
8368         };
8369
8370         var getWeakData = function (it, create) {
8371           if (!has$1(it, METADATA)) {
8372             // can't set metadata to uncaught frozen object
8373             if (!isExtensible(it)) return true;
8374             // not necessary to add metadata
8375             if (!create) return false;
8376             // add missing metadata
8377             setMetadata(it);
8378           // return the store of weak collections IDs
8379           } return it[METADATA].weakData;
8380         };
8381
8382         // add metadata on freeze-family methods calling
8383         var onFreeze = function (it) {
8384           if (freezing && meta.REQUIRED && isExtensible(it) && !has$1(it, METADATA)) setMetadata(it);
8385           return it;
8386         };
8387
8388         var meta = module.exports = {
8389           REQUIRED: false,
8390           fastKey: fastKey,
8391           getWeakData: getWeakData,
8392           onFreeze: onFreeze
8393         };
8394
8395         hiddenKeys$1[METADATA] = true;
8396         });
8397
8398         var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
8399           var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
8400           var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
8401           var ADDER = IS_MAP ? 'set' : 'add';
8402           var NativeConstructor = global$2[CONSTRUCTOR_NAME];
8403           var NativePrototype = NativeConstructor && NativeConstructor.prototype;
8404           var Constructor = NativeConstructor;
8405           var exported = {};
8406
8407           var fixMethod = function (KEY) {
8408             var nativeMethod = NativePrototype[KEY];
8409             redefine(NativePrototype, KEY,
8410               KEY == 'add' ? function add(value) {
8411                 nativeMethod.call(this, value === 0 ? 0 : value);
8412                 return this;
8413               } : KEY == 'delete' ? function (key) {
8414                 return IS_WEAK && !isObject$4(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
8415               } : KEY == 'get' ? function get(key) {
8416                 return IS_WEAK && !isObject$4(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
8417               } : KEY == 'has' ? function has(key) {
8418                 return IS_WEAK && !isObject$4(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
8419               } : function set(key, value) {
8420                 nativeMethod.call(this, key === 0 ? 0 : key, value);
8421                 return this;
8422               }
8423             );
8424           };
8425
8426           var REPLACE = isForced_1(
8427             CONSTRUCTOR_NAME,
8428             typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
8429               new NativeConstructor().entries().next();
8430             }))
8431           );
8432
8433           if (REPLACE) {
8434             // create collection constructor
8435             Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
8436             internalMetadata.REQUIRED = true;
8437           } else if (isForced_1(CONSTRUCTOR_NAME, true)) {
8438             var instance = new Constructor();
8439             // early implementations not supports chaining
8440             var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;
8441             // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
8442             var THROWS_ON_PRIMITIVES = fails(function () { instance.has(1); });
8443             // most early implementations doesn't supports iterables, most modern - not close it correctly
8444             // eslint-disable-next-line no-new -- required for testing
8445             var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) { new NativeConstructor(iterable); });
8446             // for early implementations -0 and +0 not the same
8447             var BUGGY_ZERO = !IS_WEAK && fails(function () {
8448               // V8 ~ Chromium 42- fails only with 5+ elements
8449               var $instance = new NativeConstructor();
8450               var index = 5;
8451               while (index--) $instance[ADDER](index, index);
8452               return !$instance.has(-0);
8453             });
8454
8455             if (!ACCEPT_ITERABLES) {
8456               Constructor = wrapper(function (dummy, iterable) {
8457                 anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
8458                 var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
8459                 if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
8460                 return that;
8461               });
8462               Constructor.prototype = NativePrototype;
8463               NativePrototype.constructor = Constructor;
8464             }
8465
8466             if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
8467               fixMethod('delete');
8468               fixMethod('has');
8469               IS_MAP && fixMethod('get');
8470             }
8471
8472             if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);
8473
8474             // weak collections should not contains .clear method
8475             if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
8476           }
8477
8478           exported[CONSTRUCTOR_NAME] = Constructor;
8479           _export({ global: true, forced: Constructor != NativeConstructor }, exported);
8480
8481           setToStringTag(Constructor, CONSTRUCTOR_NAME);
8482
8483           if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
8484
8485           return Constructor;
8486         };
8487
8488         var defineProperty$2 = objectDefineProperty.f;
8489
8490
8491
8492
8493
8494
8495
8496
8497         var fastKey = internalMetadata.fastKey;
8498
8499
8500         var setInternalState = internalState.set;
8501         var internalStateGetterFor = internalState.getterFor;
8502
8503         var collectionStrong = {
8504           getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
8505             var C = wrapper(function (that, iterable) {
8506               anInstance(that, C, CONSTRUCTOR_NAME);
8507               setInternalState(that, {
8508                 type: CONSTRUCTOR_NAME,
8509                 index: objectCreate(null),
8510                 first: undefined,
8511                 last: undefined,
8512                 size: 0
8513               });
8514               if (!descriptors) that.size = 0;
8515               if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
8516             });
8517
8518             var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
8519
8520             var define = function (that, key, value) {
8521               var state = getInternalState(that);
8522               var entry = getEntry(that, key);
8523               var previous, index;
8524               // change existing entry
8525               if (entry) {
8526                 entry.value = value;
8527               // create new entry
8528               } else {
8529                 state.last = entry = {
8530                   index: index = fastKey(key, true),
8531                   key: key,
8532                   value: value,
8533                   previous: previous = state.last,
8534                   next: undefined,
8535                   removed: false
8536                 };
8537                 if (!state.first) state.first = entry;
8538                 if (previous) previous.next = entry;
8539                 if (descriptors) state.size++;
8540                 else that.size++;
8541                 // add to index
8542                 if (index !== 'F') state.index[index] = entry;
8543               } return that;
8544             };
8545
8546             var getEntry = function (that, key) {
8547               var state = getInternalState(that);
8548               // fast case
8549               var index = fastKey(key);
8550               var entry;
8551               if (index !== 'F') return state.index[index];
8552               // frozen object case
8553               for (entry = state.first; entry; entry = entry.next) {
8554                 if (entry.key == key) return entry;
8555               }
8556             };
8557
8558             redefineAll(C.prototype, {
8559               // `{ Map, Set }.prototype.clear()` methods
8560               // https://tc39.es/ecma262/#sec-map.prototype.clear
8561               // https://tc39.es/ecma262/#sec-set.prototype.clear
8562               clear: function clear() {
8563                 var that = this;
8564                 var state = getInternalState(that);
8565                 var data = state.index;
8566                 var entry = state.first;
8567                 while (entry) {
8568                   entry.removed = true;
8569                   if (entry.previous) entry.previous = entry.previous.next = undefined;
8570                   delete data[entry.index];
8571                   entry = entry.next;
8572                 }
8573                 state.first = state.last = undefined;
8574                 if (descriptors) state.size = 0;
8575                 else that.size = 0;
8576               },
8577               // `{ Map, Set }.prototype.delete(key)` methods
8578               // https://tc39.es/ecma262/#sec-map.prototype.delete
8579               // https://tc39.es/ecma262/#sec-set.prototype.delete
8580               'delete': function (key) {
8581                 var that = this;
8582                 var state = getInternalState(that);
8583                 var entry = getEntry(that, key);
8584                 if (entry) {
8585                   var next = entry.next;
8586                   var prev = entry.previous;
8587                   delete state.index[entry.index];
8588                   entry.removed = true;
8589                   if (prev) prev.next = next;
8590                   if (next) next.previous = prev;
8591                   if (state.first == entry) state.first = next;
8592                   if (state.last == entry) state.last = prev;
8593                   if (descriptors) state.size--;
8594                   else that.size--;
8595                 } return !!entry;
8596               },
8597               // `{ Map, Set }.prototype.forEach(callbackfn, thisArg = undefined)` methods
8598               // https://tc39.es/ecma262/#sec-map.prototype.foreach
8599               // https://tc39.es/ecma262/#sec-set.prototype.foreach
8600               forEach: function forEach(callbackfn /* , that = undefined */) {
8601                 var state = getInternalState(this);
8602                 var boundFunction = functionBindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
8603                 var entry;
8604                 while (entry = entry ? entry.next : state.first) {
8605                   boundFunction(entry.value, entry.key, this);
8606                   // revert to the last existing entry
8607                   while (entry && entry.removed) entry = entry.previous;
8608                 }
8609               },
8610               // `{ Map, Set}.prototype.has(key)` methods
8611               // https://tc39.es/ecma262/#sec-map.prototype.has
8612               // https://tc39.es/ecma262/#sec-set.prototype.has
8613               has: function has(key) {
8614                 return !!getEntry(this, key);
8615               }
8616             });
8617
8618             redefineAll(C.prototype, IS_MAP ? {
8619               // `Map.prototype.get(key)` method
8620               // https://tc39.es/ecma262/#sec-map.prototype.get
8621               get: function get(key) {
8622                 var entry = getEntry(this, key);
8623                 return entry && entry.value;
8624               },
8625               // `Map.prototype.set(key, value)` method
8626               // https://tc39.es/ecma262/#sec-map.prototype.set
8627               set: function set(key, value) {
8628                 return define(this, key === 0 ? 0 : key, value);
8629               }
8630             } : {
8631               // `Set.prototype.add(value)` method
8632               // https://tc39.es/ecma262/#sec-set.prototype.add
8633               add: function add(value) {
8634                 return define(this, value = value === 0 ? 0 : value, value);
8635               }
8636             });
8637             if (descriptors) defineProperty$2(C.prototype, 'size', {
8638               get: function () {
8639                 return getInternalState(this).size;
8640               }
8641             });
8642             return C;
8643           },
8644           setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
8645             var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
8646             var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
8647             var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
8648             // `{ Map, Set }.prototype.{ keys, values, entries, @@iterator }()` methods
8649             // https://tc39.es/ecma262/#sec-map.prototype.entries
8650             // https://tc39.es/ecma262/#sec-map.prototype.keys
8651             // https://tc39.es/ecma262/#sec-map.prototype.values
8652             // https://tc39.es/ecma262/#sec-map.prototype-@@iterator
8653             // https://tc39.es/ecma262/#sec-set.prototype.entries
8654             // https://tc39.es/ecma262/#sec-set.prototype.keys
8655             // https://tc39.es/ecma262/#sec-set.prototype.values
8656             // https://tc39.es/ecma262/#sec-set.prototype-@@iterator
8657             defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
8658               setInternalState(this, {
8659                 type: ITERATOR_NAME,
8660                 target: iterated,
8661                 state: getInternalCollectionState(iterated),
8662                 kind: kind,
8663                 last: undefined
8664               });
8665             }, function () {
8666               var state = getInternalIteratorState(this);
8667               var kind = state.kind;
8668               var entry = state.last;
8669               // revert to the last existing entry
8670               while (entry && entry.removed) entry = entry.previous;
8671               // get next entry
8672               if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
8673                 // or finish the iteration
8674                 state.target = undefined;
8675                 return { value: undefined, done: true };
8676               }
8677               // return step by kind
8678               if (kind == 'keys') return { value: entry.key, done: false };
8679               if (kind == 'values') return { value: entry.value, done: false };
8680               return { value: [entry.key, entry.value], done: false };
8681             }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);
8682
8683             // `{ Map, Set }.prototype[@@species]` accessors
8684             // https://tc39.es/ecma262/#sec-get-map-@@species
8685             // https://tc39.es/ecma262/#sec-get-set-@@species
8686             setSpecies(CONSTRUCTOR_NAME);
8687           }
8688         };
8689
8690         // `Set` constructor
8691         // https://tc39.es/ecma262/#sec-set-objects
8692         collection('Set', function (init) {
8693           return function Set() { return init(this, arguments.length ? arguments[0] : undefined); };
8694         }, collectionStrong);
8695
8696         function d3_ascending (a, b) {
8697           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
8698         }
8699
8700         function d3_bisector (f) {
8701           var delta = f;
8702           var compare = f;
8703
8704           if (f.length === 1) {
8705             delta = function delta(d, x) {
8706               return f(d) - x;
8707             };
8708
8709             compare = ascendingComparator(f);
8710           }
8711
8712           function left(a, x, lo, hi) {
8713             if (lo == null) lo = 0;
8714             if (hi == null) hi = a.length;
8715
8716             while (lo < hi) {
8717               var mid = lo + hi >>> 1;
8718               if (compare(a[mid], x) < 0) lo = mid + 1;else hi = mid;
8719             }
8720
8721             return lo;
8722           }
8723
8724           function right(a, x, lo, hi) {
8725             if (lo == null) lo = 0;
8726             if (hi == null) hi = a.length;
8727
8728             while (lo < hi) {
8729               var mid = lo + hi >>> 1;
8730               if (compare(a[mid], x) > 0) hi = mid;else lo = mid + 1;
8731             }
8732
8733             return lo;
8734           }
8735
8736           function center(a, x, lo, hi) {
8737             if (lo == null) lo = 0;
8738             if (hi == null) hi = a.length;
8739             var i = left(a, x, lo, hi - 1);
8740             return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
8741           }
8742
8743           return {
8744             left: left,
8745             center: center,
8746             right: right
8747           };
8748         }
8749
8750         function ascendingComparator(f) {
8751           return function (d, x) {
8752             return d3_ascending(f(d), x);
8753           };
8754         }
8755
8756         // `Symbol.asyncIterator` well-known symbol
8757         // https://tc39.es/ecma262/#sec-symbol.asynciterator
8758         defineWellKnownSymbol('asyncIterator');
8759
8760         createCommonjsModule(function (module) {
8761           var runtime = function (exports) {
8762
8763             var Op = Object.prototype;
8764             var hasOwn = Op.hasOwnProperty;
8765             var undefined$1; // More compressible than void 0.
8766
8767             var $Symbol = typeof Symbol === "function" ? Symbol : {};
8768             var iteratorSymbol = $Symbol.iterator || "@@iterator";
8769             var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
8770             var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
8771
8772             function define(obj, key, value) {
8773               Object.defineProperty(obj, key, {
8774                 value: value,
8775                 enumerable: true,
8776                 configurable: true,
8777                 writable: true
8778               });
8779               return obj[key];
8780             }
8781
8782             try {
8783               // IE 8 has a broken Object.defineProperty that only works on DOM objects.
8784               define({}, "");
8785             } catch (err) {
8786               define = function define(obj, key, value) {
8787                 return obj[key] = value;
8788               };
8789             }
8790
8791             function wrap(innerFn, outerFn, self, tryLocsList) {
8792               // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
8793               var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
8794               var generator = Object.create(protoGenerator.prototype);
8795               var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
8796               // .throw, and .return methods.
8797
8798               generator._invoke = makeInvokeMethod(innerFn, self, context);
8799               return generator;
8800             }
8801
8802             exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
8803             // record like context.tryEntries[i].completion. This interface could
8804             // have been (and was previously) designed to take a closure to be
8805             // invoked without arguments, but in all the cases we care about we
8806             // already have an existing method we want to call, so there's no need
8807             // to create a new function object. We can even get away with assuming
8808             // the method takes exactly one argument, since that happens to be true
8809             // in every case, so we don't have to touch the arguments object. The
8810             // only additional allocation required is the completion record, which
8811             // has a stable shape and so hopefully should be cheap to allocate.
8812
8813             function tryCatch(fn, obj, arg) {
8814               try {
8815                 return {
8816                   type: "normal",
8817                   arg: fn.call(obj, arg)
8818                 };
8819               } catch (err) {
8820                 return {
8821                   type: "throw",
8822                   arg: err
8823                 };
8824               }
8825             }
8826
8827             var GenStateSuspendedStart = "suspendedStart";
8828             var GenStateSuspendedYield = "suspendedYield";
8829             var GenStateExecuting = "executing";
8830             var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
8831             // breaking out of the dispatch switch statement.
8832
8833             var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
8834             // .constructor.prototype properties for functions that return Generator
8835             // objects. For full spec compliance, you may wish to configure your
8836             // minifier not to mangle the names of these two functions.
8837
8838             function Generator() {}
8839
8840             function GeneratorFunction() {}
8841
8842             function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
8843             // don't natively support it.
8844
8845
8846             var IteratorPrototype = {};
8847
8848             IteratorPrototype[iteratorSymbol] = function () {
8849               return this;
8850             };
8851
8852             var getProto = Object.getPrototypeOf;
8853             var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
8854
8855             if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
8856               // This environment has a native %IteratorPrototype%; use it instead
8857               // of the polyfill.
8858               IteratorPrototype = NativeIteratorPrototype;
8859             }
8860
8861             var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
8862             GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
8863             GeneratorFunctionPrototype.constructor = GeneratorFunction;
8864             GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
8865             // Iterator interface in terms of a single ._invoke method.
8866
8867             function defineIteratorMethods(prototype) {
8868               ["next", "throw", "return"].forEach(function (method) {
8869                 define(prototype, method, function (arg) {
8870                   return this._invoke(method, arg);
8871                 });
8872               });
8873             }
8874
8875             exports.isGeneratorFunction = function (genFun) {
8876               var ctor = typeof genFun === "function" && genFun.constructor;
8877               return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
8878               // do is to check its .name property.
8879               (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
8880             };
8881
8882             exports.mark = function (genFun) {
8883               if (Object.setPrototypeOf) {
8884                 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
8885               } else {
8886                 genFun.__proto__ = GeneratorFunctionPrototype;
8887                 define(genFun, toStringTagSymbol, "GeneratorFunction");
8888               }
8889
8890               genFun.prototype = Object.create(Gp);
8891               return genFun;
8892             }; // Within the body of any async function, `await x` is transformed to
8893             // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
8894             // `hasOwn.call(value, "__await")` to determine if the yielded value is
8895             // meant to be awaited.
8896
8897
8898             exports.awrap = function (arg) {
8899               return {
8900                 __await: arg
8901               };
8902             };
8903
8904             function AsyncIterator(generator, PromiseImpl) {
8905               function invoke(method, arg, resolve, reject) {
8906                 var record = tryCatch(generator[method], generator, arg);
8907
8908                 if (record.type === "throw") {
8909                   reject(record.arg);
8910                 } else {
8911                   var result = record.arg;
8912                   var value = result.value;
8913
8914                   if (value && _typeof(value) === "object" && hasOwn.call(value, "__await")) {
8915                     return PromiseImpl.resolve(value.__await).then(function (value) {
8916                       invoke("next", value, resolve, reject);
8917                     }, function (err) {
8918                       invoke("throw", err, resolve, reject);
8919                     });
8920                   }
8921
8922                   return PromiseImpl.resolve(value).then(function (unwrapped) {
8923                     // When a yielded Promise is resolved, its final value becomes
8924                     // the .value of the Promise<{value,done}> result for the
8925                     // current iteration.
8926                     result.value = unwrapped;
8927                     resolve(result);
8928                   }, function (error) {
8929                     // If a rejected Promise was yielded, throw the rejection back
8930                     // into the async generator function so it can be handled there.
8931                     return invoke("throw", error, resolve, reject);
8932                   });
8933                 }
8934               }
8935
8936               var previousPromise;
8937
8938               function enqueue(method, arg) {
8939                 function callInvokeWithMethodAndArg() {
8940                   return new PromiseImpl(function (resolve, reject) {
8941                     invoke(method, arg, resolve, reject);
8942                   });
8943                 }
8944
8945                 return previousPromise = // If enqueue has been called before, then we want to wait until
8946                 // all previous Promises have been resolved before calling invoke,
8947                 // so that results are always delivered in the correct order. If
8948                 // enqueue has not been called before, then it is important to
8949                 // call invoke immediately, without waiting on a callback to fire,
8950                 // so that the async generator function has the opportunity to do
8951                 // any necessary setup in a predictable way. This predictability
8952                 // is why the Promise constructor synchronously invokes its
8953                 // executor callback, and why async functions synchronously
8954                 // execute code before the first await. Since we implement simple
8955                 // async functions in terms of async generators, it is especially
8956                 // important to get this right, even though it requires care.
8957                 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
8958                 // invocations of the iterator.
8959                 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
8960               } // Define the unified helper method that is used to implement .next,
8961               // .throw, and .return (see defineIteratorMethods).
8962
8963
8964               this._invoke = enqueue;
8965             }
8966
8967             defineIteratorMethods(AsyncIterator.prototype);
8968
8969             AsyncIterator.prototype[asyncIteratorSymbol] = function () {
8970               return this;
8971             };
8972
8973             exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
8974             // AsyncIterator objects; they just return a Promise for the value of
8975             // the final result produced by the iterator.
8976
8977             exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
8978               if (PromiseImpl === void 0) PromiseImpl = Promise;
8979               var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
8980               return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
8981               : iter.next().then(function (result) {
8982                 return result.done ? result.value : iter.next();
8983               });
8984             };
8985
8986             function makeInvokeMethod(innerFn, self, context) {
8987               var state = GenStateSuspendedStart;
8988               return function invoke(method, arg) {
8989                 if (state === GenStateExecuting) {
8990                   throw new Error("Generator is already running");
8991                 }
8992
8993                 if (state === GenStateCompleted) {
8994                   if (method === "throw") {
8995                     throw arg;
8996                   } // Be forgiving, per 25.3.3.3.3 of the spec:
8997                   // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
8998
8999
9000                   return doneResult();
9001                 }
9002
9003                 context.method = method;
9004                 context.arg = arg;
9005
9006                 while (true) {
9007                   var delegate = context.delegate;
9008
9009                   if (delegate) {
9010                     var delegateResult = maybeInvokeDelegate(delegate, context);
9011
9012                     if (delegateResult) {
9013                       if (delegateResult === ContinueSentinel) continue;
9014                       return delegateResult;
9015                     }
9016                   }
9017
9018                   if (context.method === "next") {
9019                     // Setting context._sent for legacy support of Babel's
9020                     // function.sent implementation.
9021                     context.sent = context._sent = context.arg;
9022                   } else if (context.method === "throw") {
9023                     if (state === GenStateSuspendedStart) {
9024                       state = GenStateCompleted;
9025                       throw context.arg;
9026                     }
9027
9028                     context.dispatchException(context.arg);
9029                   } else if (context.method === "return") {
9030                     context.abrupt("return", context.arg);
9031                   }
9032
9033                   state = GenStateExecuting;
9034                   var record = tryCatch(innerFn, self, context);
9035
9036                   if (record.type === "normal") {
9037                     // If an exception is thrown from innerFn, we leave state ===
9038                     // GenStateExecuting and loop back for another invocation.
9039                     state = context.done ? GenStateCompleted : GenStateSuspendedYield;
9040
9041                     if (record.arg === ContinueSentinel) {
9042                       continue;
9043                     }
9044
9045                     return {
9046                       value: record.arg,
9047                       done: context.done
9048                     };
9049                   } else if (record.type === "throw") {
9050                     state = GenStateCompleted; // Dispatch the exception by looping back around to the
9051                     // context.dispatchException(context.arg) call above.
9052
9053                     context.method = "throw";
9054                     context.arg = record.arg;
9055                   }
9056                 }
9057               };
9058             } // Call delegate.iterator[context.method](context.arg) and handle the
9059             // result, either by returning a { value, done } result from the
9060             // delegate iterator, or by modifying context.method and context.arg,
9061             // setting context.delegate to null, and returning the ContinueSentinel.
9062
9063
9064             function maybeInvokeDelegate(delegate, context) {
9065               var method = delegate.iterator[context.method];
9066
9067               if (method === undefined$1) {
9068                 // A .throw or .return when the delegate iterator has no .throw
9069                 // method always terminates the yield* loop.
9070                 context.delegate = null;
9071
9072                 if (context.method === "throw") {
9073                   // Note: ["return"] must be used for ES3 parsing compatibility.
9074                   if (delegate.iterator["return"]) {
9075                     // If the delegate iterator has a return method, give it a
9076                     // chance to clean up.
9077                     context.method = "return";
9078                     context.arg = undefined$1;
9079                     maybeInvokeDelegate(delegate, context);
9080
9081                     if (context.method === "throw") {
9082                       // If maybeInvokeDelegate(context) changed context.method from
9083                       // "return" to "throw", let that override the TypeError below.
9084                       return ContinueSentinel;
9085                     }
9086                   }
9087
9088                   context.method = "throw";
9089                   context.arg = new TypeError("The iterator does not provide a 'throw' method");
9090                 }
9091
9092                 return ContinueSentinel;
9093               }
9094
9095               var record = tryCatch(method, delegate.iterator, context.arg);
9096
9097               if (record.type === "throw") {
9098                 context.method = "throw";
9099                 context.arg = record.arg;
9100                 context.delegate = null;
9101                 return ContinueSentinel;
9102               }
9103
9104               var info = record.arg;
9105
9106               if (!info) {
9107                 context.method = "throw";
9108                 context.arg = new TypeError("iterator result is not an object");
9109                 context.delegate = null;
9110                 return ContinueSentinel;
9111               }
9112
9113               if (info.done) {
9114                 // Assign the result of the finished delegate to the temporary
9115                 // variable specified by delegate.resultName (see delegateYield).
9116                 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
9117
9118                 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
9119                 // exception, let the outer generator proceed normally. If
9120                 // context.method was "next", forget context.arg since it has been
9121                 // "consumed" by the delegate iterator. If context.method was
9122                 // "return", allow the original .return call to continue in the
9123                 // outer generator.
9124
9125                 if (context.method !== "return") {
9126                   context.method = "next";
9127                   context.arg = undefined$1;
9128                 }
9129               } else {
9130                 // Re-yield the result returned by the delegate method.
9131                 return info;
9132               } // The delegate iterator is finished, so forget it and continue with
9133               // the outer generator.
9134
9135
9136               context.delegate = null;
9137               return ContinueSentinel;
9138             } // Define Generator.prototype.{next,throw,return} in terms of the
9139             // unified ._invoke helper method.
9140
9141
9142             defineIteratorMethods(Gp);
9143             define(Gp, toStringTagSymbol, "Generator"); // A Generator should always return itself as the iterator object when the
9144             // @@iterator function is called on it. Some browsers' implementations of the
9145             // iterator prototype chain incorrectly implement this, causing the Generator
9146             // object to not be returned from this call. This ensures that doesn't happen.
9147             // See https://github.com/facebook/regenerator/issues/274 for more details.
9148
9149             Gp[iteratorSymbol] = function () {
9150               return this;
9151             };
9152
9153             Gp.toString = function () {
9154               return "[object Generator]";
9155             };
9156
9157             function pushTryEntry(locs) {
9158               var entry = {
9159                 tryLoc: locs[0]
9160               };
9161
9162               if (1 in locs) {
9163                 entry.catchLoc = locs[1];
9164               }
9165
9166               if (2 in locs) {
9167                 entry.finallyLoc = locs[2];
9168                 entry.afterLoc = locs[3];
9169               }
9170
9171               this.tryEntries.push(entry);
9172             }
9173
9174             function resetTryEntry(entry) {
9175               var record = entry.completion || {};
9176               record.type = "normal";
9177               delete record.arg;
9178               entry.completion = record;
9179             }
9180
9181             function Context(tryLocsList) {
9182               // The root entry object (effectively a try statement without a catch
9183               // or a finally block) gives us a place to store values thrown from
9184               // locations where there is no enclosing try statement.
9185               this.tryEntries = [{
9186                 tryLoc: "root"
9187               }];
9188               tryLocsList.forEach(pushTryEntry, this);
9189               this.reset(true);
9190             }
9191
9192             exports.keys = function (object) {
9193               var keys = [];
9194
9195               for (var key in object) {
9196                 keys.push(key);
9197               }
9198
9199               keys.reverse(); // Rather than returning an object with a next method, we keep
9200               // things simple and return the next function itself.
9201
9202               return function next() {
9203                 while (keys.length) {
9204                   var key = keys.pop();
9205
9206                   if (key in object) {
9207                     next.value = key;
9208                     next.done = false;
9209                     return next;
9210                   }
9211                 } // To avoid creating an additional object, we just hang the .value
9212                 // and .done properties off the next function object itself. This
9213                 // also ensures that the minifier will not anonymize the function.
9214
9215
9216                 next.done = true;
9217                 return next;
9218               };
9219             };
9220
9221             function values(iterable) {
9222               if (iterable) {
9223                 var iteratorMethod = iterable[iteratorSymbol];
9224
9225                 if (iteratorMethod) {
9226                   return iteratorMethod.call(iterable);
9227                 }
9228
9229                 if (typeof iterable.next === "function") {
9230                   return iterable;
9231                 }
9232
9233                 if (!isNaN(iterable.length)) {
9234                   var i = -1,
9235                       next = function next() {
9236                     while (++i < iterable.length) {
9237                       if (hasOwn.call(iterable, i)) {
9238                         next.value = iterable[i];
9239                         next.done = false;
9240                         return next;
9241                       }
9242                     }
9243
9244                     next.value = undefined$1;
9245                     next.done = true;
9246                     return next;
9247                   };
9248
9249                   return next.next = next;
9250                 }
9251               } // Return an iterator with no values.
9252
9253
9254               return {
9255                 next: doneResult
9256               };
9257             }
9258
9259             exports.values = values;
9260
9261             function doneResult() {
9262               return {
9263                 value: undefined$1,
9264                 done: true
9265               };
9266             }
9267
9268             Context.prototype = {
9269               constructor: Context,
9270               reset: function reset(skipTempReset) {
9271                 this.prev = 0;
9272                 this.next = 0; // Resetting context._sent for legacy support of Babel's
9273                 // function.sent implementation.
9274
9275                 this.sent = this._sent = undefined$1;
9276                 this.done = false;
9277                 this.delegate = null;
9278                 this.method = "next";
9279                 this.arg = undefined$1;
9280                 this.tryEntries.forEach(resetTryEntry);
9281
9282                 if (!skipTempReset) {
9283                   for (var name in this) {
9284                     // Not sure about the optimal order of these conditions:
9285                     if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
9286                       this[name] = undefined$1;
9287                     }
9288                   }
9289                 }
9290               },
9291               stop: function stop() {
9292                 this.done = true;
9293                 var rootEntry = this.tryEntries[0];
9294                 var rootRecord = rootEntry.completion;
9295
9296                 if (rootRecord.type === "throw") {
9297                   throw rootRecord.arg;
9298                 }
9299
9300                 return this.rval;
9301               },
9302               dispatchException: function dispatchException(exception) {
9303                 if (this.done) {
9304                   throw exception;
9305                 }
9306
9307                 var context = this;
9308
9309                 function handle(loc, caught) {
9310                   record.type = "throw";
9311                   record.arg = exception;
9312                   context.next = loc;
9313
9314                   if (caught) {
9315                     // If the dispatched exception was caught by a catch block,
9316                     // then let that catch block handle the exception normally.
9317                     context.method = "next";
9318                     context.arg = undefined$1;
9319                   }
9320
9321                   return !!caught;
9322                 }
9323
9324                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9325                   var entry = this.tryEntries[i];
9326                   var record = entry.completion;
9327
9328                   if (entry.tryLoc === "root") {
9329                     // Exception thrown outside of any try block that could handle
9330                     // it, so set the completion value of the entire function to
9331                     // throw the exception.
9332                     return handle("end");
9333                   }
9334
9335                   if (entry.tryLoc <= this.prev) {
9336                     var hasCatch = hasOwn.call(entry, "catchLoc");
9337                     var hasFinally = hasOwn.call(entry, "finallyLoc");
9338
9339                     if (hasCatch && hasFinally) {
9340                       if (this.prev < entry.catchLoc) {
9341                         return handle(entry.catchLoc, true);
9342                       } else if (this.prev < entry.finallyLoc) {
9343                         return handle(entry.finallyLoc);
9344                       }
9345                     } else if (hasCatch) {
9346                       if (this.prev < entry.catchLoc) {
9347                         return handle(entry.catchLoc, true);
9348                       }
9349                     } else if (hasFinally) {
9350                       if (this.prev < entry.finallyLoc) {
9351                         return handle(entry.finallyLoc);
9352                       }
9353                     } else {
9354                       throw new Error("try statement without catch or finally");
9355                     }
9356                   }
9357                 }
9358               },
9359               abrupt: function abrupt(type, arg) {
9360                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9361                   var entry = this.tryEntries[i];
9362
9363                   if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
9364                     var finallyEntry = entry;
9365                     break;
9366                   }
9367                 }
9368
9369                 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
9370                   // Ignore the finally entry if control is not jumping to a
9371                   // location outside the try/catch block.
9372                   finallyEntry = null;
9373                 }
9374
9375                 var record = finallyEntry ? finallyEntry.completion : {};
9376                 record.type = type;
9377                 record.arg = arg;
9378
9379                 if (finallyEntry) {
9380                   this.method = "next";
9381                   this.next = finallyEntry.finallyLoc;
9382                   return ContinueSentinel;
9383                 }
9384
9385                 return this.complete(record);
9386               },
9387               complete: function complete(record, afterLoc) {
9388                 if (record.type === "throw") {
9389                   throw record.arg;
9390                 }
9391
9392                 if (record.type === "break" || record.type === "continue") {
9393                   this.next = record.arg;
9394                 } else if (record.type === "return") {
9395                   this.rval = this.arg = record.arg;
9396                   this.method = "return";
9397                   this.next = "end";
9398                 } else if (record.type === "normal" && afterLoc) {
9399                   this.next = afterLoc;
9400                 }
9401
9402                 return ContinueSentinel;
9403               },
9404               finish: function finish(finallyLoc) {
9405                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9406                   var entry = this.tryEntries[i];
9407
9408                   if (entry.finallyLoc === finallyLoc) {
9409                     this.complete(entry.completion, entry.afterLoc);
9410                     resetTryEntry(entry);
9411                     return ContinueSentinel;
9412                   }
9413                 }
9414               },
9415               "catch": function _catch(tryLoc) {
9416                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9417                   var entry = this.tryEntries[i];
9418
9419                   if (entry.tryLoc === tryLoc) {
9420                     var record = entry.completion;
9421
9422                     if (record.type === "throw") {
9423                       var thrown = record.arg;
9424                       resetTryEntry(entry);
9425                     }
9426
9427                     return thrown;
9428                   }
9429                 } // The context.catch method must only be called with a location
9430                 // argument that corresponds to a known catch block.
9431
9432
9433                 throw new Error("illegal catch attempt");
9434               },
9435               delegateYield: function delegateYield(iterable, resultName, nextLoc) {
9436                 this.delegate = {
9437                   iterator: values(iterable),
9438                   resultName: resultName,
9439                   nextLoc: nextLoc
9440                 };
9441
9442                 if (this.method === "next") {
9443                   // Deliberately forget the last sent value so that we don't
9444                   // accidentally pass it on to the delegate.
9445                   this.arg = undefined$1;
9446                 }
9447
9448                 return ContinueSentinel;
9449               }
9450             }; // Regardless of whether this script is executing as a CommonJS module
9451             // or not, return the runtime object so that we can declare the variable
9452             // regeneratorRuntime in the outer scope, which allows this module to be
9453             // injected easily by `bin/regenerator --include-runtime script.js`.
9454
9455             return exports;
9456           }( // If this script is executing as a CommonJS module, use module.exports
9457           // as the regeneratorRuntime namespace. Otherwise create a new empty
9458           // object. Either way, the resulting object will be used to initialize
9459           // the regeneratorRuntime variable at the top of this file.
9460           module.exports );
9461
9462           try {
9463             regeneratorRuntime = runtime;
9464           } catch (accidentalStrictMode) {
9465             // This module should not be running in strict mode, so the above
9466             // assignment should always work unless something is misconfigured. Just
9467             // in case runtime.js accidentally runs in strict mode, we can escape
9468             // strict mode using a global Function call. This could conceivably fail
9469             // if a Content Security Policy forbids using Function, but in that case
9470             // the proper solution is to fix the accidental strict mode problem. If
9471             // you've misconfigured your bundler to force strict mode and applied a
9472             // CSP to forbid Function, and you're not willing to fix either of those
9473             // problems, please detail your unique predicament in a GitHub issue.
9474             Function("r", "regeneratorRuntime = r")(runtime);
9475           }
9476         });
9477
9478         var _marked$2 = /*#__PURE__*/regeneratorRuntime.mark(numbers);
9479
9480         function number$1 (x) {
9481           return x === null ? NaN : +x;
9482         }
9483         function numbers(values, valueof) {
9484           var _iterator, _step, value, index, _iterator2, _step2, _value;
9485
9486           return regeneratorRuntime.wrap(function numbers$(_context) {
9487             while (1) {
9488               switch (_context.prev = _context.next) {
9489                 case 0:
9490                   if (!(valueof === undefined)) {
9491                     _context.next = 21;
9492                     break;
9493                   }
9494
9495                   _iterator = _createForOfIteratorHelper(values);
9496                   _context.prev = 2;
9497
9498                   _iterator.s();
9499
9500                 case 4:
9501                   if ((_step = _iterator.n()).done) {
9502                     _context.next = 11;
9503                     break;
9504                   }
9505
9506                   value = _step.value;
9507
9508                   if (!(value != null && (value = +value) >= value)) {
9509                     _context.next = 9;
9510                     break;
9511                   }
9512
9513                   _context.next = 9;
9514                   return value;
9515
9516                 case 9:
9517                   _context.next = 4;
9518                   break;
9519
9520                 case 11:
9521                   _context.next = 16;
9522                   break;
9523
9524                 case 13:
9525                   _context.prev = 13;
9526                   _context.t0 = _context["catch"](2);
9527
9528                   _iterator.e(_context.t0);
9529
9530                 case 16:
9531                   _context.prev = 16;
9532
9533                   _iterator.f();
9534
9535                   return _context.finish(16);
9536
9537                 case 19:
9538                   _context.next = 40;
9539                   break;
9540
9541                 case 21:
9542                   index = -1;
9543                   _iterator2 = _createForOfIteratorHelper(values);
9544                   _context.prev = 23;
9545
9546                   _iterator2.s();
9547
9548                 case 25:
9549                   if ((_step2 = _iterator2.n()).done) {
9550                     _context.next = 32;
9551                     break;
9552                   }
9553
9554                   _value = _step2.value;
9555
9556                   if (!((_value = valueof(_value, ++index, values)) != null && (_value = +_value) >= _value)) {
9557                     _context.next = 30;
9558                     break;
9559                   }
9560
9561                   _context.next = 30;
9562                   return _value;
9563
9564                 case 30:
9565                   _context.next = 25;
9566                   break;
9567
9568                 case 32:
9569                   _context.next = 37;
9570                   break;
9571
9572                 case 34:
9573                   _context.prev = 34;
9574                   _context.t1 = _context["catch"](23);
9575
9576                   _iterator2.e(_context.t1);
9577
9578                 case 37:
9579                   _context.prev = 37;
9580
9581                   _iterator2.f();
9582
9583                   return _context.finish(37);
9584
9585                 case 40:
9586                 case "end":
9587                   return _context.stop();
9588               }
9589             }
9590           }, _marked$2, null, [[2, 13, 16, 19], [23, 34, 37, 40]]);
9591         }
9592
9593         var ascendingBisect = d3_bisector(d3_ascending);
9594         var bisectRight = ascendingBisect.right;
9595         d3_bisector(number$1).center;
9596
9597         var INCORRECT_ITERATION = !checkCorrectnessOfIteration(function (iterable) {
9598           // eslint-disable-next-line es/no-array-from -- required for testing
9599           Array.from(iterable);
9600         });
9601
9602         // `Array.from` method
9603         // https://tc39.es/ecma262/#sec-array.from
9604         _export({ target: 'Array', stat: true, forced: INCORRECT_ITERATION }, {
9605           from: arrayFrom
9606         });
9607
9608         // `Array.prototype.fill` method
9609         // https://tc39.es/ecma262/#sec-array.prototype.fill
9610         _export({ target: 'Array', proto: true }, {
9611           fill: arrayFill
9612         });
9613
9614         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
9615         addToUnscopables('fill');
9616
9617         var $some = arrayIteration.some;
9618
9619
9620         var STRICT_METHOD$3 = arrayMethodIsStrict('some');
9621
9622         // `Array.prototype.some` method
9623         // https://tc39.es/ecma262/#sec-array.prototype.some
9624         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$3 }, {
9625           some: function some(callbackfn /* , thisArg */) {
9626             return $some(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
9627           }
9628         });
9629
9630         var exportTypedArrayStaticMethod = arrayBufferViewCore.exportTypedArrayStaticMethod;
9631
9632
9633         // `%TypedArray%.from` method
9634         // https://tc39.es/ecma262/#sec-%typedarray%.from
9635         exportTypedArrayStaticMethod('from', typedArrayFrom, typedArrayConstructorsRequireWrappers);
9636
9637         // `Float64Array` constructor
9638         // https://tc39.es/ecma262/#sec-typedarray-objects
9639         typedArrayConstructor('Float64', function (init) {
9640           return function Float64Array(data, byteOffset, length) {
9641             return init(this, data, byteOffset, length);
9642           };
9643         });
9644
9645         function d3_descending (a, b) {
9646           return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
9647         }
9648
9649         // https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
9650         var Adder = /*#__PURE__*/function () {
9651           function Adder() {
9652             _classCallCheck$1(this, Adder);
9653
9654             this._partials = new Float64Array(32);
9655             this._n = 0;
9656           }
9657
9658           _createClass$1(Adder, [{
9659             key: "add",
9660             value: function add(x) {
9661               var p = this._partials;
9662               var i = 0;
9663
9664               for (var j = 0; j < this._n && j < 32; j++) {
9665                 var y = p[j],
9666                     hi = x + y,
9667                     lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
9668                 if (lo) p[i++] = lo;
9669                 x = hi;
9670               }
9671
9672               p[i] = x;
9673               this._n = i + 1;
9674               return this;
9675             }
9676           }, {
9677             key: "valueOf",
9678             value: function valueOf() {
9679               var p = this._partials;
9680               var n = this._n,
9681                   x,
9682                   y,
9683                   lo,
9684                   hi = 0;
9685
9686               if (n > 0) {
9687                 hi = p[--n];
9688
9689                 while (n > 0) {
9690                   x = hi;
9691                   y = p[--n];
9692                   hi = x + y;
9693                   lo = y - (hi - x);
9694                   if (lo) break;
9695                 }
9696
9697                 if (n > 0 && (lo < 0 && p[n - 1] < 0 || lo > 0 && p[n - 1] > 0)) {
9698                   y = lo * 2;
9699                   x = hi + y;
9700                   if (y == x - hi) hi = x;
9701                 }
9702               }
9703
9704               return hi;
9705             }
9706           }]);
9707
9708           return Adder;
9709         }();
9710
9711         // `Object.defineProperties` method
9712         // https://tc39.es/ecma262/#sec-object.defineproperties
9713         _export({ target: 'Object', stat: true, forced: !descriptors, sham: !descriptors }, {
9714           defineProperties: objectDefineProperties
9715         });
9716
9717         // `Map` constructor
9718         // https://tc39.es/ecma262/#sec-map-objects
9719         collection('Map', function (init) {
9720           return function Map() { return init(this, arguments.length ? arguments[0] : undefined); };
9721         }, collectionStrong);
9722
9723         var test = [];
9724         var nativeSort = test.sort;
9725
9726         // IE8-
9727         var FAILS_ON_UNDEFINED = fails(function () {
9728           test.sort(undefined);
9729         });
9730         // V8 bug
9731         var FAILS_ON_NULL = fails(function () {
9732           test.sort(null);
9733         });
9734         // Old WebKit
9735         var STRICT_METHOD$2 = arrayMethodIsStrict('sort');
9736
9737         var STABLE_SORT = !fails(function () {
9738           // feature detection can be too slow, so check engines versions
9739           if (engineV8Version) return engineV8Version < 70;
9740           if (engineFfVersion && engineFfVersion > 3) return;
9741           if (engineIsIeOrEdge) return true;
9742           if (engineWebkitVersion) return engineWebkitVersion < 603;
9743
9744           var result = '';
9745           var code, chr, value, index;
9746
9747           // generate an array with more 512 elements (Chakra and old V8 fails only in this case)
9748           for (code = 65; code < 76; code++) {
9749             chr = String.fromCharCode(code);
9750
9751             switch (code) {
9752               case 66: case 69: case 70: case 72: value = 3; break;
9753               case 68: case 71: value = 4; break;
9754               default: value = 2;
9755             }
9756
9757             for (index = 0; index < 47; index++) {
9758               test.push({ k: chr + index, v: value });
9759             }
9760           }
9761
9762           test.sort(function (a, b) { return b.v - a.v; });
9763
9764           for (index = 0; index < test.length; index++) {
9765             chr = test[index].k.charAt(0);
9766             if (result.charAt(result.length - 1) !== chr) result += chr;
9767           }
9768
9769           return result !== 'DGBEFHACIJK';
9770         });
9771
9772         var FORCED$5 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$2 || !STABLE_SORT;
9773
9774         var getSortCompare = function (comparefn) {
9775           return function (x, y) {
9776             if (y === undefined) return -1;
9777             if (x === undefined) return 1;
9778             if (comparefn !== undefined) return +comparefn(x, y) || 0;
9779             return String(x) > String(y) ? 1 : -1;
9780           };
9781         };
9782
9783         // `Array.prototype.sort` method
9784         // https://tc39.es/ecma262/#sec-array.prototype.sort
9785         _export({ target: 'Array', proto: true, forced: FORCED$5 }, {
9786           sort: function sort(comparefn) {
9787             if (comparefn !== undefined) aFunction(comparefn);
9788
9789             var array = toObject(this);
9790
9791             if (STABLE_SORT) return comparefn === undefined ? nativeSort.call(array) : nativeSort.call(array, comparefn);
9792
9793             var items = [];
9794             var arrayLength = toLength(array.length);
9795             var itemsLength, index;
9796
9797             for (index = 0; index < arrayLength; index++) {
9798               if (index in array) items.push(array[index]);
9799             }
9800
9801             items = arraySort(items, getSortCompare(comparefn));
9802             itemsLength = items.length;
9803             index = 0;
9804
9805             while (index < itemsLength) array[index] = items[index++];
9806             while (index < arrayLength) delete array[index++];
9807
9808             return array;
9809           }
9810         });
9811
9812         var e10 = Math.sqrt(50),
9813             e5 = Math.sqrt(10),
9814             e2 = Math.sqrt(2);
9815         function ticks (start, stop, count) {
9816           var reverse,
9817               i = -1,
9818               n,
9819               ticks,
9820               step;
9821           stop = +stop, start = +start, count = +count;
9822           if (start === stop && count > 0) return [start];
9823           if (reverse = stop < start) n = start, start = stop, stop = n;
9824           if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
9825
9826           if (step > 0) {
9827             var r0 = Math.round(start / step),
9828                 r1 = Math.round(stop / step);
9829             if (r0 * step < start) ++r0;
9830             if (r1 * step > stop) --r1;
9831             ticks = new Array(n = r1 - r0 + 1);
9832
9833             while (++i < n) {
9834               ticks[i] = (r0 + i) * step;
9835             }
9836           } else {
9837             step = -step;
9838
9839             var _r = Math.round(start * step),
9840                 _r2 = Math.round(stop * step);
9841
9842             if (_r / step < start) ++_r;
9843             if (_r2 / step > stop) --_r2;
9844             ticks = new Array(n = _r2 - _r + 1);
9845
9846             while (++i < n) {
9847               ticks[i] = (_r + i) / step;
9848             }
9849           }
9850
9851           if (reverse) ticks.reverse();
9852           return ticks;
9853         }
9854         function tickIncrement(start, stop, count) {
9855           var step = (stop - start) / Math.max(0, count),
9856               power = Math.floor(Math.log(step) / Math.LN10),
9857               error = step / Math.pow(10, power);
9858           return power >= 0 ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power) : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
9859         }
9860         function tickStep(start, stop, count) {
9861           var step0 = Math.abs(stop - start) / Math.max(0, count),
9862               step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
9863               error = step0 / step1;
9864           if (error >= e10) step1 *= 10;else if (error >= e5) step1 *= 5;else if (error >= e2) step1 *= 2;
9865           return stop < start ? -step1 : step1;
9866         }
9867
9868         function max(values, valueof) {
9869           var max;
9870
9871           if (valueof === undefined) {
9872             var _iterator = _createForOfIteratorHelper(values),
9873                 _step;
9874
9875             try {
9876               for (_iterator.s(); !(_step = _iterator.n()).done;) {
9877                 var value = _step.value;
9878
9879                 if (value != null && (max < value || max === undefined && value >= value)) {
9880                   max = value;
9881                 }
9882               }
9883             } catch (err) {
9884               _iterator.e(err);
9885             } finally {
9886               _iterator.f();
9887             }
9888           } else {
9889             var index = -1;
9890
9891             var _iterator2 = _createForOfIteratorHelper(values),
9892                 _step2;
9893
9894             try {
9895               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9896                 var _value = _step2.value;
9897
9898                 if ((_value = valueof(_value, ++index, values)) != null && (max < _value || max === undefined && _value >= _value)) {
9899                   max = _value;
9900                 }
9901               }
9902             } catch (err) {
9903               _iterator2.e(err);
9904             } finally {
9905               _iterator2.f();
9906             }
9907           }
9908
9909           return max;
9910         }
9911
9912         function min$2(values, valueof) {
9913           var min;
9914
9915           if (valueof === undefined) {
9916             var _iterator = _createForOfIteratorHelper(values),
9917                 _step;
9918
9919             try {
9920               for (_iterator.s(); !(_step = _iterator.n()).done;) {
9921                 var value = _step.value;
9922
9923                 if (value != null && (min > value || min === undefined && value >= value)) {
9924                   min = value;
9925                 }
9926               }
9927             } catch (err) {
9928               _iterator.e(err);
9929             } finally {
9930               _iterator.f();
9931             }
9932           } else {
9933             var index = -1;
9934
9935             var _iterator2 = _createForOfIteratorHelper(values),
9936                 _step2;
9937
9938             try {
9939               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9940                 var _value = _step2.value;
9941
9942                 if ((_value = valueof(_value, ++index, values)) != null && (min > _value || min === undefined && _value >= _value)) {
9943                   min = _value;
9944                 }
9945               }
9946             } catch (err) {
9947               _iterator2.e(err);
9948             } finally {
9949               _iterator2.f();
9950             }
9951           }
9952
9953           return min;
9954         }
9955
9956         // ISC license, Copyright 2018 Vladimir Agafonkin.
9957
9958         function quickselect$2(array, k) {
9959           var left = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
9960           var right = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : array.length - 1;
9961           var compare = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : d3_ascending;
9962
9963           while (right > left) {
9964             if (right - left > 600) {
9965               var n = right - left + 1;
9966               var m = k - left + 1;
9967               var z = Math.log(n);
9968               var s = 0.5 * Math.exp(2 * z / 3);
9969               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
9970               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
9971               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
9972               quickselect$2(array, k, newLeft, newRight, compare);
9973             }
9974
9975             var t = array[k];
9976             var i = left;
9977             var j = right;
9978             swap$1(array, left, k);
9979             if (compare(array[right], t) > 0) swap$1(array, left, right);
9980
9981             while (i < j) {
9982               swap$1(array, i, j), ++i, --j;
9983
9984               while (compare(array[i], t) < 0) {
9985                 ++i;
9986               }
9987
9988               while (compare(array[j], t) > 0) {
9989                 --j;
9990               }
9991             }
9992
9993             if (compare(array[left], t) === 0) swap$1(array, left, j);else ++j, swap$1(array, j, right);
9994             if (j <= k) left = j + 1;
9995             if (k <= j) right = j - 1;
9996           }
9997
9998           return array;
9999         }
10000
10001         function swap$1(array, i, j) {
10002           var t = array[i];
10003           array[i] = array[j];
10004           array[j] = t;
10005         }
10006
10007         function quantile(values, p, valueof) {
10008           values = Float64Array.from(numbers(values, valueof));
10009           if (!(n = values.length)) return;
10010           if ((p = +p) <= 0 || n < 2) return min$2(values);
10011           if (p >= 1) return max(values);
10012           var n,
10013               i = (n - 1) * p,
10014               i0 = Math.floor(i),
10015               value0 = max(quickselect$2(values, i0).subarray(0, i0 + 1)),
10016               value1 = min$2(values.subarray(i0 + 1));
10017           return value0 + (value1 - value0) * (i - i0);
10018         }
10019
10020         function d3_median (values, valueof) {
10021           return quantile(values, 0.5, valueof);
10022         }
10023
10024         var _marked$1 = /*#__PURE__*/regeneratorRuntime.mark(flatten);
10025
10026         function flatten(arrays) {
10027           var _iterator, _step, array;
10028
10029           return regeneratorRuntime.wrap(function flatten$(_context) {
10030             while (1) {
10031               switch (_context.prev = _context.next) {
10032                 case 0:
10033                   _iterator = _createForOfIteratorHelper(arrays);
10034                   _context.prev = 1;
10035
10036                   _iterator.s();
10037
10038                 case 3:
10039                   if ((_step = _iterator.n()).done) {
10040                     _context.next = 8;
10041                     break;
10042                   }
10043
10044                   array = _step.value;
10045                   return _context.delegateYield(array, "t0", 6);
10046
10047                 case 6:
10048                   _context.next = 3;
10049                   break;
10050
10051                 case 8:
10052                   _context.next = 13;
10053                   break;
10054
10055                 case 10:
10056                   _context.prev = 10;
10057                   _context.t1 = _context["catch"](1);
10058
10059                   _iterator.e(_context.t1);
10060
10061                 case 13:
10062                   _context.prev = 13;
10063
10064                   _iterator.f();
10065
10066                   return _context.finish(13);
10067
10068                 case 16:
10069                 case "end":
10070                   return _context.stop();
10071               }
10072             }
10073           }, _marked$1, null, [[1, 10, 13, 16]]);
10074         }
10075
10076         function merge$4(arrays) {
10077           return Array.from(flatten(arrays));
10078         }
10079
10080         function range$1 (start, stop, step) {
10081           start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
10082           var i = -1,
10083               n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
10084               range = new Array(n);
10085
10086           while (++i < n) {
10087             range[i] = start + i * step;
10088           }
10089
10090           return range;
10091         }
10092
10093         // `SameValue` abstract operation
10094         // https://tc39.es/ecma262/#sec-samevalue
10095         // eslint-disable-next-line es/no-object-is -- safe
10096         var sameValue = Object.is || function is(x, y) {
10097           // eslint-disable-next-line no-self-compare -- NaN check
10098           return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;
10099         };
10100
10101         // eslint-disable-next-line es/no-math-hypot -- required for testing
10102         var $hypot = Math.hypot;
10103         var abs$3 = Math.abs;
10104         var sqrt$1 = Math.sqrt;
10105
10106         // Chrome 77 bug
10107         // https://bugs.chromium.org/p/v8/issues/detail?id=9546
10108         var BUGGY = !!$hypot && $hypot(Infinity, NaN) !== Infinity;
10109
10110         // `Math.hypot` method
10111         // https://tc39.es/ecma262/#sec-math.hypot
10112         _export({ target: 'Math', stat: true, forced: BUGGY }, {
10113           // eslint-disable-next-line no-unused-vars -- required for `.length`
10114           hypot: function hypot(value1, value2) {
10115             var sum = 0;
10116             var i = 0;
10117             var aLen = arguments.length;
10118             var larg = 0;
10119             var arg, div;
10120             while (i < aLen) {
10121               arg = abs$3(arguments[i++]);
10122               if (larg < arg) {
10123                 div = larg / arg;
10124                 sum = sum * div * div + 1;
10125                 larg = arg;
10126               } else if (arg > 0) {
10127                 div = arg / larg;
10128                 sum += div * div;
10129               } else sum += arg;
10130             }
10131             return larg === Infinity ? Infinity : larg * sqrt$1(sum);
10132           }
10133         });
10134
10135         // `Math.sign` method implementation
10136         // https://tc39.es/ecma262/#sec-math.sign
10137         // eslint-disable-next-line es/no-math-sign -- safe
10138         var mathSign = Math.sign || function sign(x) {
10139           // eslint-disable-next-line no-self-compare -- NaN check
10140           return (x = +x) == 0 || x != x ? x : x < 0 ? -1 : 1;
10141         };
10142
10143         // `Math.sign` method
10144         // https://tc39.es/ecma262/#sec-math.sign
10145         _export({ target: 'Math', stat: true }, {
10146           sign: mathSign
10147         });
10148
10149         var epsilon$1 = 1e-6;
10150         var epsilon2$1 = 1e-12;
10151         var pi = Math.PI;
10152         var halfPi = pi / 2;
10153         var quarterPi = pi / 4;
10154         var tau = pi * 2;
10155         var degrees$1 = 180 / pi;
10156         var radians = pi / 180;
10157         var abs$2 = Math.abs;
10158         var atan = Math.atan;
10159         var atan2 = Math.atan2;
10160         var cos = Math.cos;
10161         var exp$2 = Math.exp;
10162         var log$1 = Math.log;
10163         var sin = Math.sin;
10164         var sign = Math.sign || function (x) {
10165           return x > 0 ? 1 : x < 0 ? -1 : 0;
10166         };
10167         var sqrt = Math.sqrt;
10168         var tan = Math.tan;
10169         function acos(x) {
10170           return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
10171         }
10172         function asin(x) {
10173           return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
10174         }
10175
10176         function noop$1() {}
10177
10178         function streamGeometry(geometry, stream) {
10179           if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
10180             streamGeometryType[geometry.type](geometry, stream);
10181           }
10182         }
10183
10184         var streamObjectType = {
10185           Feature: function Feature(object, stream) {
10186             streamGeometry(object.geometry, stream);
10187           },
10188           FeatureCollection: function FeatureCollection(object, stream) {
10189             var features = object.features,
10190                 i = -1,
10191                 n = features.length;
10192
10193             while (++i < n) {
10194               streamGeometry(features[i].geometry, stream);
10195             }
10196           }
10197         };
10198         var streamGeometryType = {
10199           Sphere: function Sphere(object, stream) {
10200             stream.sphere();
10201           },
10202           Point: function Point(object, stream) {
10203             object = object.coordinates;
10204             stream.point(object[0], object[1], object[2]);
10205           },
10206           MultiPoint: function MultiPoint(object, stream) {
10207             var coordinates = object.coordinates,
10208                 i = -1,
10209                 n = coordinates.length;
10210
10211             while (++i < n) {
10212               object = coordinates[i], stream.point(object[0], object[1], object[2]);
10213             }
10214           },
10215           LineString: function LineString(object, stream) {
10216             streamLine(object.coordinates, stream, 0);
10217           },
10218           MultiLineString: function MultiLineString(object, stream) {
10219             var coordinates = object.coordinates,
10220                 i = -1,
10221                 n = coordinates.length;
10222
10223             while (++i < n) {
10224               streamLine(coordinates[i], stream, 0);
10225             }
10226           },
10227           Polygon: function Polygon(object, stream) {
10228             streamPolygon(object.coordinates, stream);
10229           },
10230           MultiPolygon: function MultiPolygon(object, stream) {
10231             var coordinates = object.coordinates,
10232                 i = -1,
10233                 n = coordinates.length;
10234
10235             while (++i < n) {
10236               streamPolygon(coordinates[i], stream);
10237             }
10238           },
10239           GeometryCollection: function GeometryCollection(object, stream) {
10240             var geometries = object.geometries,
10241                 i = -1,
10242                 n = geometries.length;
10243
10244             while (++i < n) {
10245               streamGeometry(geometries[i], stream);
10246             }
10247           }
10248         };
10249
10250         function streamLine(coordinates, stream, closed) {
10251           var i = -1,
10252               n = coordinates.length - closed,
10253               coordinate;
10254           stream.lineStart();
10255
10256           while (++i < n) {
10257             coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
10258           }
10259
10260           stream.lineEnd();
10261         }
10262
10263         function streamPolygon(coordinates, stream) {
10264           var i = -1,
10265               n = coordinates.length;
10266           stream.polygonStart();
10267
10268           while (++i < n) {
10269             streamLine(coordinates[i], stream, 1);
10270           }
10271
10272           stream.polygonEnd();
10273         }
10274
10275         function d3_geoStream (object, stream) {
10276           if (object && streamObjectType.hasOwnProperty(object.type)) {
10277             streamObjectType[object.type](object, stream);
10278           } else {
10279             streamGeometry(object, stream);
10280           }
10281         }
10282
10283         var areaRingSum$1 = new Adder(); // hello?
10284
10285         var areaSum$1 = new Adder(),
10286             lambda00$1,
10287             phi00$1,
10288             lambda0$2,
10289             cosPhi0$1,
10290             sinPhi0$1;
10291         var areaStream$1 = {
10292           point: noop$1,
10293           lineStart: noop$1,
10294           lineEnd: noop$1,
10295           polygonStart: function polygonStart() {
10296             areaRingSum$1 = new Adder();
10297             areaStream$1.lineStart = areaRingStart$1;
10298             areaStream$1.lineEnd = areaRingEnd$1;
10299           },
10300           polygonEnd: function polygonEnd() {
10301             var areaRing = +areaRingSum$1;
10302             areaSum$1.add(areaRing < 0 ? tau + areaRing : areaRing);
10303             this.lineStart = this.lineEnd = this.point = noop$1;
10304           },
10305           sphere: function sphere() {
10306             areaSum$1.add(tau);
10307           }
10308         };
10309
10310         function areaRingStart$1() {
10311           areaStream$1.point = areaPointFirst$1;
10312         }
10313
10314         function areaRingEnd$1() {
10315           areaPoint$1(lambda00$1, phi00$1);
10316         }
10317
10318         function areaPointFirst$1(lambda, phi) {
10319           areaStream$1.point = areaPoint$1;
10320           lambda00$1 = lambda, phi00$1 = phi;
10321           lambda *= radians, phi *= radians;
10322           lambda0$2 = lambda, cosPhi0$1 = cos(phi = phi / 2 + quarterPi), sinPhi0$1 = sin(phi);
10323         }
10324
10325         function areaPoint$1(lambda, phi) {
10326           lambda *= radians, phi *= radians;
10327           phi = phi / 2 + quarterPi; // half the angular distance from south pole
10328           // Spherical excess E for a spherical triangle with vertices: south pole,
10329           // previous point, current point.  Uses a formula derived from Cagnoli’s
10330           // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
10331
10332           var dLambda = lambda - lambda0$2,
10333               sdLambda = dLambda >= 0 ? 1 : -1,
10334               adLambda = sdLambda * dLambda,
10335               cosPhi = cos(phi),
10336               sinPhi = sin(phi),
10337               k = sinPhi0$1 * sinPhi,
10338               u = cosPhi0$1 * cosPhi + k * cos(adLambda),
10339               v = k * sdLambda * sin(adLambda);
10340           areaRingSum$1.add(atan2(v, u)); // Advance the previous points.
10341
10342           lambda0$2 = lambda, cosPhi0$1 = cosPhi, sinPhi0$1 = sinPhi;
10343         }
10344
10345         function d3_geoArea (object) {
10346           areaSum$1 = new Adder();
10347           d3_geoStream(object, areaStream$1);
10348           return areaSum$1 * 2;
10349         }
10350
10351         function spherical(cartesian) {
10352           return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
10353         }
10354         function cartesian(spherical) {
10355           var lambda = spherical[0],
10356               phi = spherical[1],
10357               cosPhi = cos(phi);
10358           return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
10359         }
10360         function cartesianDot(a, b) {
10361           return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
10362         }
10363         function cartesianCross(a, b) {
10364           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]];
10365         } // TODO return a
10366
10367         function cartesianAddInPlace(a, b) {
10368           a[0] += b[0], a[1] += b[1], a[2] += b[2];
10369         }
10370         function cartesianScale(vector, k) {
10371           return [vector[0] * k, vector[1] * k, vector[2] * k];
10372         } // TODO return d
10373
10374         function cartesianNormalizeInPlace(d) {
10375           var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
10376           d[0] /= l, d[1] /= l, d[2] /= l;
10377         }
10378
10379         var lambda0$1, phi0, lambda1, phi1, // bounds
10380         lambda2, // previous lambda-coordinate
10381         lambda00, phi00, // first point
10382         p0, // previous 3D point
10383         deltaSum, ranges, range;
10384         var boundsStream$1 = {
10385           point: boundsPoint$1,
10386           lineStart: boundsLineStart,
10387           lineEnd: boundsLineEnd,
10388           polygonStart: function polygonStart() {
10389             boundsStream$1.point = boundsRingPoint;
10390             boundsStream$1.lineStart = boundsRingStart;
10391             boundsStream$1.lineEnd = boundsRingEnd;
10392             deltaSum = new Adder();
10393             areaStream$1.polygonStart();
10394           },
10395           polygonEnd: function polygonEnd() {
10396             areaStream$1.polygonEnd();
10397             boundsStream$1.point = boundsPoint$1;
10398             boundsStream$1.lineStart = boundsLineStart;
10399             boundsStream$1.lineEnd = boundsLineEnd;
10400             if (areaRingSum$1 < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);else if (deltaSum > epsilon$1) phi1 = 90;else if (deltaSum < -epsilon$1) phi0 = -90;
10401             range[0] = lambda0$1, range[1] = lambda1;
10402           },
10403           sphere: function sphere() {
10404             lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
10405           }
10406         };
10407
10408         function boundsPoint$1(lambda, phi) {
10409           ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
10410           if (phi < phi0) phi0 = phi;
10411           if (phi > phi1) phi1 = phi;
10412         }
10413
10414         function linePoint(lambda, phi) {
10415           var p = cartesian([lambda * radians, phi * radians]);
10416
10417           if (p0) {
10418             var normal = cartesianCross(p0, p),
10419                 equatorial = [normal[1], -normal[0], 0],
10420                 inflection = cartesianCross(equatorial, normal);
10421             cartesianNormalizeInPlace(inflection);
10422             inflection = spherical(inflection);
10423             var delta = lambda - lambda2,
10424                 sign = delta > 0 ? 1 : -1,
10425                 lambdai = inflection[0] * degrees$1 * sign,
10426                 phii,
10427                 antimeridian = abs$2(delta) > 180;
10428
10429             if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
10430               phii = inflection[1] * degrees$1;
10431               if (phii > phi1) phi1 = phii;
10432             } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
10433               phii = -inflection[1] * degrees$1;
10434               if (phii < phi0) phi0 = phii;
10435             } else {
10436               if (phi < phi0) phi0 = phi;
10437               if (phi > phi1) phi1 = phi;
10438             }
10439
10440             if (antimeridian) {
10441               if (lambda < lambda2) {
10442                 if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
10443               } else {
10444                 if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
10445               }
10446             } else {
10447               if (lambda1 >= lambda0$1) {
10448                 if (lambda < lambda0$1) lambda0$1 = lambda;
10449                 if (lambda > lambda1) lambda1 = lambda;
10450               } else {
10451                 if (lambda > lambda2) {
10452                   if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
10453                 } else {
10454                   if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
10455                 }
10456               }
10457             }
10458           } else {
10459             ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
10460           }
10461
10462           if (phi < phi0) phi0 = phi;
10463           if (phi > phi1) phi1 = phi;
10464           p0 = p, lambda2 = lambda;
10465         }
10466
10467         function boundsLineStart() {
10468           boundsStream$1.point = linePoint;
10469         }
10470
10471         function boundsLineEnd() {
10472           range[0] = lambda0$1, range[1] = lambda1;
10473           boundsStream$1.point = boundsPoint$1;
10474           p0 = null;
10475         }
10476
10477         function boundsRingPoint(lambda, phi) {
10478           if (p0) {
10479             var delta = lambda - lambda2;
10480             deltaSum.add(abs$2(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
10481           } else {
10482             lambda00 = lambda, phi00 = phi;
10483           }
10484
10485           areaStream$1.point(lambda, phi);
10486           linePoint(lambda, phi);
10487         }
10488
10489         function boundsRingStart() {
10490           areaStream$1.lineStart();
10491         }
10492
10493         function boundsRingEnd() {
10494           boundsRingPoint(lambda00, phi00);
10495           areaStream$1.lineEnd();
10496           if (abs$2(deltaSum) > epsilon$1) lambda0$1 = -(lambda1 = 180);
10497           range[0] = lambda0$1, range[1] = lambda1;
10498           p0 = null;
10499         } // Finds the left-right distance between two longitudes.
10500         // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
10501         // the distance between ±180° to be 360°.
10502
10503
10504         function angle(lambda0, lambda1) {
10505           return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
10506         }
10507
10508         function rangeCompare(a, b) {
10509           return a[0] - b[0];
10510         }
10511
10512         function rangeContains(range, x) {
10513           return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
10514         }
10515
10516         function d3_geoBounds (feature) {
10517           var i, n, a, b, merged, deltaMax, delta;
10518           phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
10519           ranges = [];
10520           d3_geoStream(feature, boundsStream$1); // First, sort ranges by their minimum longitudes.
10521
10522           if (n = ranges.length) {
10523             ranges.sort(rangeCompare); // Then, merge any ranges that overlap.
10524
10525             for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
10526               b = ranges[i];
10527
10528               if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
10529                 if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
10530                 if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
10531               } else {
10532                 merged.push(a = b);
10533               }
10534             } // Finally, find the largest gap between the merged ranges.
10535             // The final bounding box will be the inverse of this gap.
10536
10537
10538             for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
10539               b = merged[i];
10540               if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
10541             }
10542           }
10543
10544           ranges = range = null;
10545           return lambda0$1 === Infinity || phi0 === Infinity ? [[NaN, NaN], [NaN, NaN]] : [[lambda0$1, phi0], [lambda1, phi1]];
10546         }
10547
10548         function compose (a, b) {
10549           function compose(x, y) {
10550             return x = a(x, y), b(x[0], x[1]);
10551           }
10552
10553           if (a.invert && b.invert) compose.invert = function (x, y) {
10554             return x = b.invert(x, y), x && a.invert(x[0], x[1]);
10555           };
10556           return compose;
10557         }
10558
10559         function rotationIdentity(lambda, phi) {
10560           return [abs$2(lambda) > pi ? lambda + Math.round(-lambda / tau) * tau : lambda, phi];
10561         }
10562
10563         rotationIdentity.invert = rotationIdentity;
10564         function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
10565           return (deltaLambda %= tau) ? deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma)) : rotationLambda(deltaLambda) : deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma) : rotationIdentity;
10566         }
10567
10568         function forwardRotationLambda(deltaLambda) {
10569           return function (lambda, phi) {
10570             return lambda += deltaLambda, [lambda > pi ? lambda - tau : lambda < -pi ? lambda + tau : lambda, phi];
10571           };
10572         }
10573
10574         function rotationLambda(deltaLambda) {
10575           var rotation = forwardRotationLambda(deltaLambda);
10576           rotation.invert = forwardRotationLambda(-deltaLambda);
10577           return rotation;
10578         }
10579
10580         function rotationPhiGamma(deltaPhi, deltaGamma) {
10581           var cosDeltaPhi = cos(deltaPhi),
10582               sinDeltaPhi = sin(deltaPhi),
10583               cosDeltaGamma = cos(deltaGamma),
10584               sinDeltaGamma = sin(deltaGamma);
10585
10586           function rotation(lambda, phi) {
10587             var cosPhi = cos(phi),
10588                 x = cos(lambda) * cosPhi,
10589                 y = sin(lambda) * cosPhi,
10590                 z = sin(phi),
10591                 k = z * cosDeltaPhi + x * sinDeltaPhi;
10592             return [atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi), asin(k * cosDeltaGamma + y * sinDeltaGamma)];
10593           }
10594
10595           rotation.invert = function (lambda, phi) {
10596             var cosPhi = cos(phi),
10597                 x = cos(lambda) * cosPhi,
10598                 y = sin(lambda) * cosPhi,
10599                 z = sin(phi),
10600                 k = z * cosDeltaGamma - y * sinDeltaGamma;
10601             return [atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi), asin(k * cosDeltaPhi - x * sinDeltaPhi)];
10602           };
10603
10604           return rotation;
10605         }
10606
10607         function rotation (rotate) {
10608           rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
10609
10610           function forward(coordinates) {
10611             coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
10612             return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
10613           }
10614
10615           forward.invert = function (coordinates) {
10616             coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
10617             return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
10618           };
10619
10620           return forward;
10621         }
10622
10623         function circleStream(stream, radius, delta, direction, t0, t1) {
10624           if (!delta) return;
10625           var cosRadius = cos(radius),
10626               sinRadius = sin(radius),
10627               step = direction * delta;
10628
10629           if (t0 == null) {
10630             t0 = radius + direction * tau;
10631             t1 = radius - step / 2;
10632           } else {
10633             t0 = circleRadius(cosRadius, t0);
10634             t1 = circleRadius(cosRadius, t1);
10635             if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
10636           }
10637
10638           for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
10639             point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
10640             stream.point(point[0], point[1]);
10641           }
10642         } // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
10643
10644         function circleRadius(cosRadius, point) {
10645           point = cartesian(point), point[0] -= cosRadius;
10646           cartesianNormalizeInPlace(point);
10647           var radius = acos(-point[1]);
10648           return ((-point[2] < 0 ? -radius : radius) + tau - epsilon$1) % tau;
10649         }
10650
10651         function clipBuffer () {
10652           var lines = [],
10653               line;
10654           return {
10655             point: function point(x, y, m) {
10656               line.push([x, y, m]);
10657             },
10658             lineStart: function lineStart() {
10659               lines.push(line = []);
10660             },
10661             lineEnd: noop$1,
10662             rejoin: function rejoin() {
10663               if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
10664             },
10665             result: function result() {
10666               var result = lines;
10667               lines = [];
10668               line = null;
10669               return result;
10670             }
10671           };
10672         }
10673
10674         function pointEqual (a, b) {
10675           return abs$2(a[0] - b[0]) < epsilon$1 && abs$2(a[1] - b[1]) < epsilon$1;
10676         }
10677
10678         function Intersection(point, points, other, entry) {
10679           this.x = point;
10680           this.z = points;
10681           this.o = other; // another intersection
10682
10683           this.e = entry; // is an entry?
10684
10685           this.v = false; // visited
10686
10687           this.n = this.p = null; // next & previous
10688         } // A generalized polygon clipping algorithm: given a polygon that has been cut
10689         // into its visible line segments, and rejoins the segments by interpolating
10690         // along the clip edge.
10691
10692
10693         function clipRejoin (segments, compareIntersection, startInside, interpolate, stream) {
10694           var subject = [],
10695               clip = [],
10696               i,
10697               n;
10698           segments.forEach(function (segment) {
10699             if ((n = segment.length - 1) <= 0) return;
10700             var n,
10701                 p0 = segment[0],
10702                 p1 = segment[n],
10703                 x;
10704
10705             if (pointEqual(p0, p1)) {
10706               if (!p0[2] && !p1[2]) {
10707                 stream.lineStart();
10708
10709                 for (i = 0; i < n; ++i) {
10710                   stream.point((p0 = segment[i])[0], p0[1]);
10711                 }
10712
10713                 stream.lineEnd();
10714                 return;
10715               } // handle degenerate cases by moving the point
10716
10717
10718               p1[0] += 2 * epsilon$1;
10719             }
10720
10721             subject.push(x = new Intersection(p0, segment, null, true));
10722             clip.push(x.o = new Intersection(p0, null, x, false));
10723             subject.push(x = new Intersection(p1, segment, null, false));
10724             clip.push(x.o = new Intersection(p1, null, x, true));
10725           });
10726           if (!subject.length) return;
10727           clip.sort(compareIntersection);
10728           link(subject);
10729           link(clip);
10730
10731           for (i = 0, n = clip.length; i < n; ++i) {
10732             clip[i].e = startInside = !startInside;
10733           }
10734
10735           var start = subject[0],
10736               points,
10737               point;
10738
10739           while (1) {
10740             // Find first unvisited intersection.
10741             var current = start,
10742                 isSubject = true;
10743
10744             while (current.v) {
10745               if ((current = current.n) === start) return;
10746             }
10747
10748             points = current.z;
10749             stream.lineStart();
10750
10751             do {
10752               current.v = current.o.v = true;
10753
10754               if (current.e) {
10755                 if (isSubject) {
10756                   for (i = 0, n = points.length; i < n; ++i) {
10757                     stream.point((point = points[i])[0], point[1]);
10758                   }
10759                 } else {
10760                   interpolate(current.x, current.n.x, 1, stream);
10761                 }
10762
10763                 current = current.n;
10764               } else {
10765                 if (isSubject) {
10766                   points = current.p.z;
10767
10768                   for (i = points.length - 1; i >= 0; --i) {
10769                     stream.point((point = points[i])[0], point[1]);
10770                   }
10771                 } else {
10772                   interpolate(current.x, current.p.x, -1, stream);
10773                 }
10774
10775                 current = current.p;
10776               }
10777
10778               current = current.o;
10779               points = current.z;
10780               isSubject = !isSubject;
10781             } while (!current.v);
10782
10783             stream.lineEnd();
10784           }
10785         }
10786
10787         function link(array) {
10788           if (!(n = array.length)) return;
10789           var n,
10790               i = 0,
10791               a = array[0],
10792               b;
10793
10794           while (++i < n) {
10795             a.n = b = array[i];
10796             b.p = a;
10797             a = b;
10798           }
10799
10800           a.n = b = array[0];
10801           b.p = a;
10802         }
10803
10804         function longitude(point) {
10805           if (abs$2(point[0]) <= pi) return point[0];else return sign(point[0]) * ((abs$2(point[0]) + pi) % tau - pi);
10806         }
10807
10808         function polygonContains (polygon, point) {
10809           var lambda = longitude(point),
10810               phi = point[1],
10811               sinPhi = sin(phi),
10812               normal = [sin(lambda), -cos(lambda), 0],
10813               angle = 0,
10814               winding = 0;
10815           var sum = new Adder();
10816           if (sinPhi === 1) phi = halfPi + epsilon$1;else if (sinPhi === -1) phi = -halfPi - epsilon$1;
10817
10818           for (var i = 0, n = polygon.length; i < n; ++i) {
10819             if (!(m = (ring = polygon[i]).length)) continue;
10820             var ring,
10821                 m,
10822                 point0 = ring[m - 1],
10823                 lambda0 = longitude(point0),
10824                 phi0 = point0[1] / 2 + quarterPi,
10825                 sinPhi0 = sin(phi0),
10826                 cosPhi0 = cos(phi0);
10827
10828             for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
10829               var point1 = ring[j],
10830                   lambda1 = longitude(point1),
10831                   phi1 = point1[1] / 2 + quarterPi,
10832                   sinPhi1 = sin(phi1),
10833                   cosPhi1 = cos(phi1),
10834                   delta = lambda1 - lambda0,
10835                   sign = delta >= 0 ? 1 : -1,
10836                   absDelta = sign * delta,
10837                   antimeridian = absDelta > pi,
10838                   k = sinPhi0 * sinPhi1;
10839               sum.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
10840               angle += antimeridian ? delta + sign * tau : delta; // Are the longitudes either side of the point’s meridian (lambda),
10841               // and are the latitudes smaller than the parallel (phi)?
10842
10843               if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
10844                 var arc = cartesianCross(cartesian(point0), cartesian(point1));
10845                 cartesianNormalizeInPlace(arc);
10846                 var intersection = cartesianCross(normal, arc);
10847                 cartesianNormalizeInPlace(intersection);
10848                 var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
10849
10850                 if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
10851                   winding += antimeridian ^ delta >= 0 ? 1 : -1;
10852                 }
10853               }
10854             }
10855           } // First, determine whether the South pole is inside or outside:
10856           //
10857           // It is inside if:
10858           // * the polygon winds around it in a clockwise direction.
10859           // * the polygon does not (cumulatively) wind around it, but has a negative
10860           //   (counter-clockwise) area.
10861           //
10862           // Second, count the (signed) number of times a segment crosses a lambda
10863           // from the point to the South pole.  If it is zero, then the point is the
10864           // same side as the South pole.
10865
10866
10867           return (angle < -epsilon$1 || angle < epsilon$1 && sum < -epsilon2$1) ^ winding & 1;
10868         }
10869
10870         function clip (pointVisible, clipLine, interpolate, start) {
10871           return function (sink) {
10872             var line = clipLine(sink),
10873                 ringBuffer = clipBuffer(),
10874                 ringSink = clipLine(ringBuffer),
10875                 polygonStarted = false,
10876                 polygon,
10877                 segments,
10878                 ring;
10879             var clip = {
10880               point: point,
10881               lineStart: lineStart,
10882               lineEnd: lineEnd,
10883               polygonStart: function polygonStart() {
10884                 clip.point = pointRing;
10885                 clip.lineStart = ringStart;
10886                 clip.lineEnd = ringEnd;
10887                 segments = [];
10888                 polygon = [];
10889               },
10890               polygonEnd: function polygonEnd() {
10891                 clip.point = point;
10892                 clip.lineStart = lineStart;
10893                 clip.lineEnd = lineEnd;
10894                 segments = merge$4(segments);
10895                 var startInside = polygonContains(polygon, start);
10896
10897                 if (segments.length) {
10898                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10899                   clipRejoin(segments, compareIntersection, startInside, interpolate, sink);
10900                 } else if (startInside) {
10901                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10902                   sink.lineStart();
10903                   interpolate(null, null, 1, sink);
10904                   sink.lineEnd();
10905                 }
10906
10907                 if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
10908                 segments = polygon = null;
10909               },
10910               sphere: function sphere() {
10911                 sink.polygonStart();
10912                 sink.lineStart();
10913                 interpolate(null, null, 1, sink);
10914                 sink.lineEnd();
10915                 sink.polygonEnd();
10916               }
10917             };
10918
10919             function point(lambda, phi) {
10920               if (pointVisible(lambda, phi)) sink.point(lambda, phi);
10921             }
10922
10923             function pointLine(lambda, phi) {
10924               line.point(lambda, phi);
10925             }
10926
10927             function lineStart() {
10928               clip.point = pointLine;
10929               line.lineStart();
10930             }
10931
10932             function lineEnd() {
10933               clip.point = point;
10934               line.lineEnd();
10935             }
10936
10937             function pointRing(lambda, phi) {
10938               ring.push([lambda, phi]);
10939               ringSink.point(lambda, phi);
10940             }
10941
10942             function ringStart() {
10943               ringSink.lineStart();
10944               ring = [];
10945             }
10946
10947             function ringEnd() {
10948               pointRing(ring[0][0], ring[0][1]);
10949               ringSink.lineEnd();
10950               var clean = ringSink.clean(),
10951                   ringSegments = ringBuffer.result(),
10952                   i,
10953                   n = ringSegments.length,
10954                   m,
10955                   segment,
10956                   point;
10957               ring.pop();
10958               polygon.push(ring);
10959               ring = null;
10960               if (!n) return; // No intersections.
10961
10962               if (clean & 1) {
10963                 segment = ringSegments[0];
10964
10965                 if ((m = segment.length - 1) > 0) {
10966                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10967                   sink.lineStart();
10968
10969                   for (i = 0; i < m; ++i) {
10970                     sink.point((point = segment[i])[0], point[1]);
10971                   }
10972
10973                   sink.lineEnd();
10974                 }
10975
10976                 return;
10977               } // Rejoin connected segments.
10978               // TODO reuse ringBuffer.rejoin()?
10979
10980
10981               if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
10982               segments.push(ringSegments.filter(validSegment));
10983             }
10984
10985             return clip;
10986           };
10987         }
10988
10989         function validSegment(segment) {
10990           return segment.length > 1;
10991         } // Intersections are sorted along the clip edge. For both antimeridian cutting
10992         // and circle clipping, the same comparison is used.
10993
10994
10995         function compareIntersection(a, b) {
10996           return ((a = a.x)[0] < 0 ? a[1] - halfPi - epsilon$1 : halfPi - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfPi - epsilon$1 : halfPi - b[1]);
10997         }
10998
10999         var clipAntimeridian = clip(function () {
11000           return true;
11001         }, clipAntimeridianLine, clipAntimeridianInterpolate, [-pi, -halfPi]); // Takes a line and cuts into visible segments. Return values: 0 - there were
11002         // intersections or the line was empty; 1 - no intersections; 2 - there were
11003         // intersections, and the first and last segments should be rejoined.
11004
11005         function clipAntimeridianLine(stream) {
11006           var lambda0 = NaN,
11007               phi0 = NaN,
11008               sign0 = NaN,
11009               _clean; // no intersections
11010
11011
11012           return {
11013             lineStart: function lineStart() {
11014               stream.lineStart();
11015               _clean = 1;
11016             },
11017             point: function point(lambda1, phi1) {
11018               var sign1 = lambda1 > 0 ? pi : -pi,
11019                   delta = abs$2(lambda1 - lambda0);
11020
11021               if (abs$2(delta - pi) < epsilon$1) {
11022                 // line crosses a pole
11023                 stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi : -halfPi);
11024                 stream.point(sign0, phi0);
11025                 stream.lineEnd();
11026                 stream.lineStart();
11027                 stream.point(sign1, phi0);
11028                 stream.point(lambda1, phi0);
11029                 _clean = 0;
11030               } else if (sign0 !== sign1 && delta >= pi) {
11031                 // line crosses antimeridian
11032                 if (abs$2(lambda0 - sign0) < epsilon$1) lambda0 -= sign0 * epsilon$1; // handle degeneracies
11033
11034                 if (abs$2(lambda1 - sign1) < epsilon$1) lambda1 -= sign1 * epsilon$1;
11035                 phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
11036                 stream.point(sign0, phi0);
11037                 stream.lineEnd();
11038                 stream.lineStart();
11039                 stream.point(sign1, phi0);
11040                 _clean = 0;
11041               }
11042
11043               stream.point(lambda0 = lambda1, phi0 = phi1);
11044               sign0 = sign1;
11045             },
11046             lineEnd: function lineEnd() {
11047               stream.lineEnd();
11048               lambda0 = phi0 = NaN;
11049             },
11050             clean: function clean() {
11051               return 2 - _clean; // if intersections, rejoin first and last segments
11052             }
11053           };
11054         }
11055
11056         function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
11057           var cosPhi0,
11058               cosPhi1,
11059               sinLambda0Lambda1 = sin(lambda0 - lambda1);
11060           return abs$2(sinLambda0Lambda1) > epsilon$1 ? atan((sin(phi0) * (cosPhi1 = cos(phi1)) * sin(lambda1) - sin(phi1) * (cosPhi0 = cos(phi0)) * sin(lambda0)) / (cosPhi0 * cosPhi1 * sinLambda0Lambda1)) : (phi0 + phi1) / 2;
11061         }
11062
11063         function clipAntimeridianInterpolate(from, to, direction, stream) {
11064           var phi;
11065
11066           if (from == null) {
11067             phi = direction * halfPi;
11068             stream.point(-pi, phi);
11069             stream.point(0, phi);
11070             stream.point(pi, phi);
11071             stream.point(pi, 0);
11072             stream.point(pi, -phi);
11073             stream.point(0, -phi);
11074             stream.point(-pi, -phi);
11075             stream.point(-pi, 0);
11076             stream.point(-pi, phi);
11077           } else if (abs$2(from[0] - to[0]) > epsilon$1) {
11078             var lambda = from[0] < to[0] ? pi : -pi;
11079             phi = direction * lambda / 2;
11080             stream.point(-lambda, phi);
11081             stream.point(0, phi);
11082             stream.point(lambda, phi);
11083           } else {
11084             stream.point(to[0], to[1]);
11085           }
11086         }
11087
11088         function clipCircle (radius) {
11089           var cr = cos(radius),
11090               delta = 6 * radians,
11091               smallRadius = cr > 0,
11092               notHemisphere = abs$2(cr) > epsilon$1; // TODO optimise for this common case
11093
11094           function interpolate(from, to, direction, stream) {
11095             circleStream(stream, radius, delta, direction, from, to);
11096           }
11097
11098           function visible(lambda, phi) {
11099             return cos(lambda) * cos(phi) > cr;
11100           } // Takes a line and cuts into visible segments. Return values used for polygon
11101           // clipping: 0 - there were intersections or the line was empty; 1 - no
11102           // intersections 2 - there were intersections, and the first and last segments
11103           // should be rejoined.
11104
11105
11106           function clipLine(stream) {
11107             var point0, // previous point
11108             c0, // code for previous point
11109             v0, // visibility of previous point
11110             v00, // visibility of first point
11111             _clean; // no intersections
11112
11113
11114             return {
11115               lineStart: function lineStart() {
11116                 v00 = v0 = false;
11117                 _clean = 1;
11118               },
11119               point: function point(lambda, phi) {
11120                 var point1 = [lambda, phi],
11121                     point2,
11122                     v = visible(lambda, phi),
11123                     c = smallRadius ? v ? 0 : code(lambda, phi) : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
11124                 if (!point0 && (v00 = v0 = v)) stream.lineStart();
11125
11126                 if (v !== v0) {
11127                   point2 = intersect(point0, point1);
11128                   if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) point1[2] = 1;
11129                 }
11130
11131                 if (v !== v0) {
11132                   _clean = 0;
11133
11134                   if (v) {
11135                     // outside going in
11136                     stream.lineStart();
11137                     point2 = intersect(point1, point0);
11138                     stream.point(point2[0], point2[1]);
11139                   } else {
11140                     // inside going out
11141                     point2 = intersect(point0, point1);
11142                     stream.point(point2[0], point2[1], 2);
11143                     stream.lineEnd();
11144                   }
11145
11146                   point0 = point2;
11147                 } else if (notHemisphere && point0 && smallRadius ^ v) {
11148                   var t; // If the codes for two points are different, or are both zero,
11149                   // and there this segment intersects with the small circle.
11150
11151                   if (!(c & c0) && (t = intersect(point1, point0, true))) {
11152                     _clean = 0;
11153
11154                     if (smallRadius) {
11155                       stream.lineStart();
11156                       stream.point(t[0][0], t[0][1]);
11157                       stream.point(t[1][0], t[1][1]);
11158                       stream.lineEnd();
11159                     } else {
11160                       stream.point(t[1][0], t[1][1]);
11161                       stream.lineEnd();
11162                       stream.lineStart();
11163                       stream.point(t[0][0], t[0][1], 3);
11164                     }
11165                   }
11166                 }
11167
11168                 if (v && (!point0 || !pointEqual(point0, point1))) {
11169                   stream.point(point1[0], point1[1]);
11170                 }
11171
11172                 point0 = point1, v0 = v, c0 = c;
11173               },
11174               lineEnd: function lineEnd() {
11175                 if (v0) stream.lineEnd();
11176                 point0 = null;
11177               },
11178               // Rejoin first and last segments if there were intersections and the first
11179               // and last points were visible.
11180               clean: function clean() {
11181                 return _clean | (v00 && v0) << 1;
11182               }
11183             };
11184           } // Intersects the great circle between a and b with the clip circle.
11185
11186
11187           function intersect(a, b, two) {
11188             var pa = cartesian(a),
11189                 pb = cartesian(b); // We have two planes, n1.p = d1 and n2.p = d2.
11190             // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
11191
11192             var n1 = [1, 0, 0],
11193                 // normal
11194             n2 = cartesianCross(pa, pb),
11195                 n2n2 = cartesianDot(n2, n2),
11196                 n1n2 = n2[0],
11197                 // cartesianDot(n1, n2),
11198             determinant = n2n2 - n1n2 * n1n2; // Two polar points.
11199
11200             if (!determinant) return !two && a;
11201             var c1 = cr * n2n2 / determinant,
11202                 c2 = -cr * n1n2 / determinant,
11203                 n1xn2 = cartesianCross(n1, n2),
11204                 A = cartesianScale(n1, c1),
11205                 B = cartesianScale(n2, c2);
11206             cartesianAddInPlace(A, B); // Solve |p(t)|^2 = 1.
11207
11208             var u = n1xn2,
11209                 w = cartesianDot(A, u),
11210                 uu = cartesianDot(u, u),
11211                 t2 = w * w - uu * (cartesianDot(A, A) - 1);
11212             if (t2 < 0) return;
11213             var t = sqrt(t2),
11214                 q = cartesianScale(u, (-w - t) / uu);
11215             cartesianAddInPlace(q, A);
11216             q = spherical(q);
11217             if (!two) return q; // Two intersection points.
11218
11219             var lambda0 = a[0],
11220                 lambda1 = b[0],
11221                 phi0 = a[1],
11222                 phi1 = b[1],
11223                 z;
11224             if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
11225             var delta = lambda1 - lambda0,
11226                 polar = abs$2(delta - pi) < epsilon$1,
11227                 meridian = polar || delta < epsilon$1;
11228             if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; // Check that the first point is between a and b.
11229
11230             if (meridian ? polar ? phi0 + phi1 > 0 ^ q[1] < (abs$2(q[0] - lambda0) < epsilon$1 ? phi0 : phi1) : phi0 <= q[1] && q[1] <= phi1 : delta > pi ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
11231               var q1 = cartesianScale(u, (-w + t) / uu);
11232               cartesianAddInPlace(q1, A);
11233               return [q, spherical(q1)];
11234             }
11235           } // Generates a 4-bit vector representing the location of a point relative to
11236           // the small circle's bounding box.
11237
11238
11239           function code(lambda, phi) {
11240             var r = smallRadius ? radius : pi - radius,
11241                 code = 0;
11242             if (lambda < -r) code |= 1; // left
11243             else if (lambda > r) code |= 2; // right
11244
11245             if (phi < -r) code |= 4; // below
11246             else if (phi > r) code |= 8; // above
11247
11248             return code;
11249           }
11250
11251           return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
11252         }
11253
11254         function clipLine (a, b, x0, y0, x1, y1) {
11255           var ax = a[0],
11256               ay = a[1],
11257               bx = b[0],
11258               by = b[1],
11259               t0 = 0,
11260               t1 = 1,
11261               dx = bx - ax,
11262               dy = by - ay,
11263               r;
11264           r = x0 - ax;
11265           if (!dx && r > 0) return;
11266           r /= dx;
11267
11268           if (dx < 0) {
11269             if (r < t0) return;
11270             if (r < t1) t1 = r;
11271           } else if (dx > 0) {
11272             if (r > t1) return;
11273             if (r > t0) t0 = r;
11274           }
11275
11276           r = x1 - ax;
11277           if (!dx && r < 0) return;
11278           r /= dx;
11279
11280           if (dx < 0) {
11281             if (r > t1) return;
11282             if (r > t0) t0 = r;
11283           } else if (dx > 0) {
11284             if (r < t0) return;
11285             if (r < t1) t1 = r;
11286           }
11287
11288           r = y0 - ay;
11289           if (!dy && r > 0) return;
11290           r /= dy;
11291
11292           if (dy < 0) {
11293             if (r < t0) return;
11294             if (r < t1) t1 = r;
11295           } else if (dy > 0) {
11296             if (r > t1) return;
11297             if (r > t0) t0 = r;
11298           }
11299
11300           r = y1 - ay;
11301           if (!dy && r < 0) return;
11302           r /= dy;
11303
11304           if (dy < 0) {
11305             if (r > t1) return;
11306             if (r > t0) t0 = r;
11307           } else if (dy > 0) {
11308             if (r < t0) return;
11309             if (r < t1) t1 = r;
11310           }
11311
11312           if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
11313           if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
11314           return true;
11315         }
11316
11317         var clipMax = 1e9,
11318             clipMin = -clipMax; // TODO Use d3-polygon’s polygonContains here for the ring check?
11319         // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
11320
11321         function clipRectangle(x0, y0, x1, y1) {
11322           function visible(x, y) {
11323             return x0 <= x && x <= x1 && y0 <= y && y <= y1;
11324           }
11325
11326           function interpolate(from, to, direction, stream) {
11327             var a = 0,
11328                 a1 = 0;
11329
11330             if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoint(from, to) < 0 ^ direction > 0) {
11331               do {
11332                 stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
11333               } while ((a = (a + direction + 4) % 4) !== a1);
11334             } else {
11335               stream.point(to[0], to[1]);
11336             }
11337           }
11338
11339           function corner(p, direction) {
11340             return abs$2(p[0] - x0) < epsilon$1 ? direction > 0 ? 0 : 3 : abs$2(p[0] - x1) < epsilon$1 ? direction > 0 ? 2 : 1 : abs$2(p[1] - y0) < epsilon$1 ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
11341           }
11342
11343           function compareIntersection(a, b) {
11344             return comparePoint(a.x, b.x);
11345           }
11346
11347           function comparePoint(a, b) {
11348             var ca = corner(a, 1),
11349                 cb = corner(b, 1);
11350             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];
11351           }
11352
11353           return function (stream) {
11354             var activeStream = stream,
11355                 bufferStream = clipBuffer(),
11356                 segments,
11357                 polygon,
11358                 ring,
11359                 x__,
11360                 y__,
11361                 v__,
11362                 // first point
11363             x_,
11364                 y_,
11365                 v_,
11366                 // previous point
11367             first,
11368                 clean;
11369             var clipStream = {
11370               point: point,
11371               lineStart: lineStart,
11372               lineEnd: lineEnd,
11373               polygonStart: polygonStart,
11374               polygonEnd: polygonEnd
11375             };
11376
11377             function point(x, y) {
11378               if (visible(x, y)) activeStream.point(x, y);
11379             }
11380
11381             function polygonInside() {
11382               var winding = 0;
11383
11384               for (var i = 0, n = polygon.length; i < n; ++i) {
11385                 for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
11386                   a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
11387
11388                   if (a1 <= y1) {
11389                     if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding;
11390                   } else {
11391                     if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding;
11392                   }
11393                 }
11394               }
11395
11396               return winding;
11397             } // Buffer geometry within a polygon and then clip it en masse.
11398
11399
11400             function polygonStart() {
11401               activeStream = bufferStream, segments = [], polygon = [], clean = true;
11402             }
11403
11404             function polygonEnd() {
11405               var startInside = polygonInside(),
11406                   cleanInside = clean && startInside,
11407                   visible = (segments = merge$4(segments)).length;
11408
11409               if (cleanInside || visible) {
11410                 stream.polygonStart();
11411
11412                 if (cleanInside) {
11413                   stream.lineStart();
11414                   interpolate(null, null, 1, stream);
11415                   stream.lineEnd();
11416                 }
11417
11418                 if (visible) {
11419                   clipRejoin(segments, compareIntersection, startInside, interpolate, stream);
11420                 }
11421
11422                 stream.polygonEnd();
11423               }
11424
11425               activeStream = stream, segments = polygon = ring = null;
11426             }
11427
11428             function lineStart() {
11429               clipStream.point = linePoint;
11430               if (polygon) polygon.push(ring = []);
11431               first = true;
11432               v_ = false;
11433               x_ = y_ = NaN;
11434             } // TODO rather than special-case polygons, simply handle them separately.
11435             // Ideally, coincident intersection points should be jittered to avoid
11436             // clipping issues.
11437
11438
11439             function lineEnd() {
11440               if (segments) {
11441                 linePoint(x__, y__);
11442                 if (v__ && v_) bufferStream.rejoin();
11443                 segments.push(bufferStream.result());
11444               }
11445
11446               clipStream.point = point;
11447               if (v_) activeStream.lineEnd();
11448             }
11449
11450             function linePoint(x, y) {
11451               var v = visible(x, y);
11452               if (polygon) ring.push([x, y]);
11453
11454               if (first) {
11455                 x__ = x, y__ = y, v__ = v;
11456                 first = false;
11457
11458                 if (v) {
11459                   activeStream.lineStart();
11460                   activeStream.point(x, y);
11461                 }
11462               } else {
11463                 if (v && v_) activeStream.point(x, y);else {
11464                   var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
11465                       b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
11466
11467                   if (clipLine(a, b, x0, y0, x1, y1)) {
11468                     if (!v_) {
11469                       activeStream.lineStart();
11470                       activeStream.point(a[0], a[1]);
11471                     }
11472
11473                     activeStream.point(b[0], b[1]);
11474                     if (!v) activeStream.lineEnd();
11475                     clean = false;
11476                   } else if (v) {
11477                     activeStream.lineStart();
11478                     activeStream.point(x, y);
11479                     clean = false;
11480                   }
11481                 }
11482               }
11483
11484               x_ = x, y_ = y, v_ = v;
11485             }
11486
11487             return clipStream;
11488           };
11489         }
11490
11491         var lengthSum$1, lambda0, sinPhi0, cosPhi0;
11492         var lengthStream$1 = {
11493           sphere: noop$1,
11494           point: noop$1,
11495           lineStart: lengthLineStart,
11496           lineEnd: noop$1,
11497           polygonStart: noop$1,
11498           polygonEnd: noop$1
11499         };
11500
11501         function lengthLineStart() {
11502           lengthStream$1.point = lengthPointFirst$1;
11503           lengthStream$1.lineEnd = lengthLineEnd;
11504         }
11505
11506         function lengthLineEnd() {
11507           lengthStream$1.point = lengthStream$1.lineEnd = noop$1;
11508         }
11509
11510         function lengthPointFirst$1(lambda, phi) {
11511           lambda *= radians, phi *= radians;
11512           lambda0 = lambda, sinPhi0 = sin(phi), cosPhi0 = cos(phi);
11513           lengthStream$1.point = lengthPoint$1;
11514         }
11515
11516         function lengthPoint$1(lambda, phi) {
11517           lambda *= radians, phi *= radians;
11518           var sinPhi = sin(phi),
11519               cosPhi = cos(phi),
11520               delta = abs$2(lambda - lambda0),
11521               cosDelta = cos(delta),
11522               sinDelta = sin(delta),
11523               x = cosPhi * sinDelta,
11524               y = cosPhi0 * sinPhi - sinPhi0 * cosPhi * cosDelta,
11525               z = sinPhi0 * sinPhi + cosPhi0 * cosPhi * cosDelta;
11526           lengthSum$1.add(atan2(sqrt(x * x + y * y), z));
11527           lambda0 = lambda, sinPhi0 = sinPhi, cosPhi0 = cosPhi;
11528         }
11529
11530         function d3_geoLength (object) {
11531           lengthSum$1 = new Adder();
11532           d3_geoStream(object, lengthStream$1);
11533           return +lengthSum$1;
11534         }
11535
11536         var identity$4 = (function (x) {
11537           return x;
11538         });
11539
11540         var areaSum = new Adder(),
11541             areaRingSum = new Adder(),
11542             x00$2,
11543             y00$2,
11544             x0$3,
11545             y0$3;
11546         var areaStream = {
11547           point: noop$1,
11548           lineStart: noop$1,
11549           lineEnd: noop$1,
11550           polygonStart: function polygonStart() {
11551             areaStream.lineStart = areaRingStart;
11552             areaStream.lineEnd = areaRingEnd;
11553           },
11554           polygonEnd: function polygonEnd() {
11555             areaStream.lineStart = areaStream.lineEnd = areaStream.point = noop$1;
11556             areaSum.add(abs$2(areaRingSum));
11557             areaRingSum = new Adder();
11558           },
11559           result: function result() {
11560             var area = areaSum / 2;
11561             areaSum = new Adder();
11562             return area;
11563           }
11564         };
11565
11566         function areaRingStart() {
11567           areaStream.point = areaPointFirst;
11568         }
11569
11570         function areaPointFirst(x, y) {
11571           areaStream.point = areaPoint;
11572           x00$2 = x0$3 = x, y00$2 = y0$3 = y;
11573         }
11574
11575         function areaPoint(x, y) {
11576           areaRingSum.add(y0$3 * x - x0$3 * y);
11577           x0$3 = x, y0$3 = y;
11578         }
11579
11580         function areaRingEnd() {
11581           areaPoint(x00$2, y00$2);
11582         }
11583
11584         var x0$2 = Infinity,
11585             y0$2 = x0$2,
11586             x1 = -x0$2,
11587             y1 = x1;
11588         var boundsStream = {
11589           point: boundsPoint,
11590           lineStart: noop$1,
11591           lineEnd: noop$1,
11592           polygonStart: noop$1,
11593           polygonEnd: noop$1,
11594           result: function result() {
11595             var bounds = [[x0$2, y0$2], [x1, y1]];
11596             x1 = y1 = -(y0$2 = x0$2 = Infinity);
11597             return bounds;
11598           }
11599         };
11600
11601         function boundsPoint(x, y) {
11602           if (x < x0$2) x0$2 = x;
11603           if (x > x1) x1 = x;
11604           if (y < y0$2) y0$2 = y;
11605           if (y > y1) y1 = y;
11606         }
11607
11608         var X0 = 0,
11609             Y0 = 0,
11610             Z0 = 0,
11611             X1 = 0,
11612             Y1 = 0,
11613             Z1 = 0,
11614             X2 = 0,
11615             Y2 = 0,
11616             Z2 = 0,
11617             x00$1,
11618             y00$1,
11619             x0$1,
11620             y0$1;
11621         var centroidStream = {
11622           point: centroidPoint,
11623           lineStart: centroidLineStart,
11624           lineEnd: centroidLineEnd,
11625           polygonStart: function polygonStart() {
11626             centroidStream.lineStart = centroidRingStart;
11627             centroidStream.lineEnd = centroidRingEnd;
11628           },
11629           polygonEnd: function polygonEnd() {
11630             centroidStream.point = centroidPoint;
11631             centroidStream.lineStart = centroidLineStart;
11632             centroidStream.lineEnd = centroidLineEnd;
11633           },
11634           result: function result() {
11635             var centroid = Z2 ? [X2 / Z2, Y2 / Z2] : Z1 ? [X1 / Z1, Y1 / Z1] : Z0 ? [X0 / Z0, Y0 / Z0] : [NaN, NaN];
11636             X0 = Y0 = Z0 = X1 = Y1 = Z1 = X2 = Y2 = Z2 = 0;
11637             return centroid;
11638           }
11639         };
11640
11641         function centroidPoint(x, y) {
11642           X0 += x;
11643           Y0 += y;
11644           ++Z0;
11645         }
11646
11647         function centroidLineStart() {
11648           centroidStream.point = centroidPointFirstLine;
11649         }
11650
11651         function centroidPointFirstLine(x, y) {
11652           centroidStream.point = centroidPointLine;
11653           centroidPoint(x0$1 = x, y0$1 = y);
11654         }
11655
11656         function centroidPointLine(x, y) {
11657           var dx = x - x0$1,
11658               dy = y - y0$1,
11659               z = sqrt(dx * dx + dy * dy);
11660           X1 += z * (x0$1 + x) / 2;
11661           Y1 += z * (y0$1 + y) / 2;
11662           Z1 += z;
11663           centroidPoint(x0$1 = x, y0$1 = y);
11664         }
11665
11666         function centroidLineEnd() {
11667           centroidStream.point = centroidPoint;
11668         }
11669
11670         function centroidRingStart() {
11671           centroidStream.point = centroidPointFirstRing;
11672         }
11673
11674         function centroidRingEnd() {
11675           centroidPointRing(x00$1, y00$1);
11676         }
11677
11678         function centroidPointFirstRing(x, y) {
11679           centroidStream.point = centroidPointRing;
11680           centroidPoint(x00$1 = x0$1 = x, y00$1 = y0$1 = y);
11681         }
11682
11683         function centroidPointRing(x, y) {
11684           var dx = x - x0$1,
11685               dy = y - y0$1,
11686               z = sqrt(dx * dx + dy * dy);
11687           X1 += z * (x0$1 + x) / 2;
11688           Y1 += z * (y0$1 + y) / 2;
11689           Z1 += z;
11690           z = y0$1 * x - x0$1 * y;
11691           X2 += z * (x0$1 + x);
11692           Y2 += z * (y0$1 + y);
11693           Z2 += z * 3;
11694           centroidPoint(x0$1 = x, y0$1 = y);
11695         }
11696
11697         function PathContext(context) {
11698           this._context = context;
11699         }
11700         PathContext.prototype = {
11701           _radius: 4.5,
11702           pointRadius: function pointRadius(_) {
11703             return this._radius = _, this;
11704           },
11705           polygonStart: function polygonStart() {
11706             this._line = 0;
11707           },
11708           polygonEnd: function polygonEnd() {
11709             this._line = NaN;
11710           },
11711           lineStart: function lineStart() {
11712             this._point = 0;
11713           },
11714           lineEnd: function lineEnd() {
11715             if (this._line === 0) this._context.closePath();
11716             this._point = NaN;
11717           },
11718           point: function point(x, y) {
11719             switch (this._point) {
11720               case 0:
11721                 {
11722                   this._context.moveTo(x, y);
11723
11724                   this._point = 1;
11725                   break;
11726                 }
11727
11728               case 1:
11729                 {
11730                   this._context.lineTo(x, y);
11731
11732                   break;
11733                 }
11734
11735               default:
11736                 {
11737                   this._context.moveTo(x + this._radius, y);
11738
11739                   this._context.arc(x, y, this._radius, 0, tau);
11740
11741                   break;
11742                 }
11743             }
11744           },
11745           result: noop$1
11746         };
11747
11748         var lengthSum = new Adder(),
11749             lengthRing,
11750             x00,
11751             y00,
11752             x0,
11753             y0;
11754         var lengthStream = {
11755           point: noop$1,
11756           lineStart: function lineStart() {
11757             lengthStream.point = lengthPointFirst;
11758           },
11759           lineEnd: function lineEnd() {
11760             if (lengthRing) lengthPoint(x00, y00);
11761             lengthStream.point = noop$1;
11762           },
11763           polygonStart: function polygonStart() {
11764             lengthRing = true;
11765           },
11766           polygonEnd: function polygonEnd() {
11767             lengthRing = null;
11768           },
11769           result: function result() {
11770             var length = +lengthSum;
11771             lengthSum = new Adder();
11772             return length;
11773           }
11774         };
11775
11776         function lengthPointFirst(x, y) {
11777           lengthStream.point = lengthPoint;
11778           x00 = x0 = x, y00 = y0 = y;
11779         }
11780
11781         function lengthPoint(x, y) {
11782           x0 -= x, y0 -= y;
11783           lengthSum.add(sqrt(x0 * x0 + y0 * y0));
11784           x0 = x, y0 = y;
11785         }
11786
11787         function PathString() {
11788           this._string = [];
11789         }
11790         PathString.prototype = {
11791           _radius: 4.5,
11792           _circle: circle(4.5),
11793           pointRadius: function pointRadius(_) {
11794             if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
11795             return this;
11796           },
11797           polygonStart: function polygonStart() {
11798             this._line = 0;
11799           },
11800           polygonEnd: function polygonEnd() {
11801             this._line = NaN;
11802           },
11803           lineStart: function lineStart() {
11804             this._point = 0;
11805           },
11806           lineEnd: function lineEnd() {
11807             if (this._line === 0) this._string.push("Z");
11808             this._point = NaN;
11809           },
11810           point: function point(x, y) {
11811             switch (this._point) {
11812               case 0:
11813                 {
11814                   this._string.push("M", x, ",", y);
11815
11816                   this._point = 1;
11817                   break;
11818                 }
11819
11820               case 1:
11821                 {
11822                   this._string.push("L", x, ",", y);
11823
11824                   break;
11825                 }
11826
11827               default:
11828                 {
11829                   if (this._circle == null) this._circle = circle(this._radius);
11830
11831                   this._string.push("M", x, ",", y, this._circle);
11832
11833                   break;
11834                 }
11835             }
11836           },
11837           result: function result() {
11838             if (this._string.length) {
11839               var result = this._string.join("");
11840
11841               this._string = [];
11842               return result;
11843             } else {
11844               return null;
11845             }
11846           }
11847         };
11848
11849         function circle(radius) {
11850           return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
11851         }
11852
11853         function d3_geoPath (projection, context) {
11854           var pointRadius = 4.5,
11855               projectionStream,
11856               contextStream;
11857
11858           function path(object) {
11859             if (object) {
11860               if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
11861               d3_geoStream(object, projectionStream(contextStream));
11862             }
11863
11864             return contextStream.result();
11865           }
11866
11867           path.area = function (object) {
11868             d3_geoStream(object, projectionStream(areaStream));
11869             return areaStream.result();
11870           };
11871
11872           path.measure = function (object) {
11873             d3_geoStream(object, projectionStream(lengthStream));
11874             return lengthStream.result();
11875           };
11876
11877           path.bounds = function (object) {
11878             d3_geoStream(object, projectionStream(boundsStream));
11879             return boundsStream.result();
11880           };
11881
11882           path.centroid = function (object) {
11883             d3_geoStream(object, projectionStream(centroidStream));
11884             return centroidStream.result();
11885           };
11886
11887           path.projection = function (_) {
11888             return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$4) : (projection = _).stream, path) : projection;
11889           };
11890
11891           path.context = function (_) {
11892             if (!arguments.length) return context;
11893             contextStream = _ == null ? (context = null, new PathString()) : new PathContext(context = _);
11894             if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
11895             return path;
11896           };
11897
11898           path.pointRadius = function (_) {
11899             if (!arguments.length) return pointRadius;
11900             pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
11901             return path;
11902           };
11903
11904           return path.projection(projection).context(context);
11905         }
11906
11907         function d3_geoTransform (methods) {
11908           return {
11909             stream: transformer$1(methods)
11910           };
11911         }
11912         function transformer$1(methods) {
11913           return function (stream) {
11914             var s = new TransformStream();
11915
11916             for (var key in methods) {
11917               s[key] = methods[key];
11918             }
11919
11920             s.stream = stream;
11921             return s;
11922           };
11923         }
11924
11925         function TransformStream() {}
11926
11927         TransformStream.prototype = {
11928           constructor: TransformStream,
11929           point: function point(x, y) {
11930             this.stream.point(x, y);
11931           },
11932           sphere: function sphere() {
11933             this.stream.sphere();
11934           },
11935           lineStart: function lineStart() {
11936             this.stream.lineStart();
11937           },
11938           lineEnd: function lineEnd() {
11939             this.stream.lineEnd();
11940           },
11941           polygonStart: function polygonStart() {
11942             this.stream.polygonStart();
11943           },
11944           polygonEnd: function polygonEnd() {
11945             this.stream.polygonEnd();
11946           }
11947         };
11948
11949         function fit(projection, fitBounds, object) {
11950           var clip = projection.clipExtent && projection.clipExtent();
11951           projection.scale(150).translate([0, 0]);
11952           if (clip != null) projection.clipExtent(null);
11953           d3_geoStream(object, projection.stream(boundsStream));
11954           fitBounds(boundsStream.result());
11955           if (clip != null) projection.clipExtent(clip);
11956           return projection;
11957         }
11958
11959         function fitExtent(projection, extent, object) {
11960           return fit(projection, function (b) {
11961             var w = extent[1][0] - extent[0][0],
11962                 h = extent[1][1] - extent[0][1],
11963                 k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
11964                 x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
11965                 y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
11966             projection.scale(150 * k).translate([x, y]);
11967           }, object);
11968         }
11969         function fitSize(projection, size, object) {
11970           return fitExtent(projection, [[0, 0], size], object);
11971         }
11972         function fitWidth(projection, width, object) {
11973           return fit(projection, function (b) {
11974             var w = +width,
11975                 k = w / (b[1][0] - b[0][0]),
11976                 x = (w - k * (b[1][0] + b[0][0])) / 2,
11977                 y = -k * b[0][1];
11978             projection.scale(150 * k).translate([x, y]);
11979           }, object);
11980         }
11981         function fitHeight(projection, height, object) {
11982           return fit(projection, function (b) {
11983             var h = +height,
11984                 k = h / (b[1][1] - b[0][1]),
11985                 x = -k * b[0][0],
11986                 y = (h - k * (b[1][1] + b[0][1])) / 2;
11987             projection.scale(150 * k).translate([x, y]);
11988           }, object);
11989         }
11990
11991         var maxDepth = 16,
11992             // maximum depth of subdivision
11993         cosMinDistance = cos(30 * radians); // cos(minimum angular distance)
11994
11995         function resample (project, delta2) {
11996           return +delta2 ? resample$1(project, delta2) : resampleNone(project);
11997         }
11998
11999         function resampleNone(project) {
12000           return transformer$1({
12001             point: function point(x, y) {
12002               x = project(x, y);
12003               this.stream.point(x[0], x[1]);
12004             }
12005           });
12006         }
12007
12008         function resample$1(project, delta2) {
12009           function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
12010             var dx = x1 - x0,
12011                 dy = y1 - y0,
12012                 d2 = dx * dx + dy * dy;
12013
12014             if (d2 > 4 * delta2 && depth--) {
12015               var a = a0 + a1,
12016                   b = b0 + b1,
12017                   c = c0 + c1,
12018                   m = sqrt(a * a + b * b + c * c),
12019                   phi2 = asin(c /= m),
12020                   lambda2 = abs$2(abs$2(c) - 1) < epsilon$1 || abs$2(lambda0 - lambda1) < epsilon$1 ? (lambda0 + lambda1) / 2 : atan2(b, a),
12021                   p = project(lambda2, phi2),
12022                   x2 = p[0],
12023                   y2 = p[1],
12024                   dx2 = x2 - x0,
12025                   dy2 = y2 - y0,
12026                   dz = dy * dx2 - dx * dy2;
12027
12028               if (dz * dz / d2 > delta2 // perpendicular projected distance
12029               || abs$2((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
12030               || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
12031                 // angular distance
12032                 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
12033                 stream.point(x2, y2);
12034                 resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
12035               }
12036             }
12037           }
12038
12039           return function (stream) {
12040             var lambda00, x00, y00, a00, b00, c00, // first point
12041             lambda0, x0, y0, a0, b0, c0; // previous point
12042
12043             var resampleStream = {
12044               point: point,
12045               lineStart: lineStart,
12046               lineEnd: lineEnd,
12047               polygonStart: function polygonStart() {
12048                 stream.polygonStart();
12049                 resampleStream.lineStart = ringStart;
12050               },
12051               polygonEnd: function polygonEnd() {
12052                 stream.polygonEnd();
12053                 resampleStream.lineStart = lineStart;
12054               }
12055             };
12056
12057             function point(x, y) {
12058               x = project(x, y);
12059               stream.point(x[0], x[1]);
12060             }
12061
12062             function lineStart() {
12063               x0 = NaN;
12064               resampleStream.point = linePoint;
12065               stream.lineStart();
12066             }
12067
12068             function linePoint(lambda, phi) {
12069               var c = cartesian([lambda, phi]),
12070                   p = project(lambda, phi);
12071               resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
12072               stream.point(x0, y0);
12073             }
12074
12075             function lineEnd() {
12076               resampleStream.point = point;
12077               stream.lineEnd();
12078             }
12079
12080             function ringStart() {
12081               lineStart();
12082               resampleStream.point = ringPoint;
12083               resampleStream.lineEnd = ringEnd;
12084             }
12085
12086             function ringPoint(lambda, phi) {
12087               linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
12088               resampleStream.point = linePoint;
12089             }
12090
12091             function ringEnd() {
12092               resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
12093               resampleStream.lineEnd = lineEnd;
12094               lineEnd();
12095             }
12096
12097             return resampleStream;
12098           };
12099         }
12100
12101         var transformRadians = transformer$1({
12102           point: function point(x, y) {
12103             this.stream.point(x * radians, y * radians);
12104           }
12105         });
12106
12107         function transformRotate(rotate) {
12108           return transformer$1({
12109             point: function point(x, y) {
12110               var r = rotate(x, y);
12111               return this.stream.point(r[0], r[1]);
12112             }
12113           });
12114         }
12115
12116         function scaleTranslate(k, dx, dy, sx, sy) {
12117           function transform(x, y) {
12118             x *= sx;
12119             y *= sy;
12120             return [dx + k * x, dy - k * y];
12121           }
12122
12123           transform.invert = function (x, y) {
12124             return [(x - dx) / k * sx, (dy - y) / k * sy];
12125           };
12126
12127           return transform;
12128         }
12129
12130         function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) {
12131           if (!alpha) return scaleTranslate(k, dx, dy, sx, sy);
12132           var cosAlpha = cos(alpha),
12133               sinAlpha = sin(alpha),
12134               a = cosAlpha * k,
12135               b = sinAlpha * k,
12136               ai = cosAlpha / k,
12137               bi = sinAlpha / k,
12138               ci = (sinAlpha * dy - cosAlpha * dx) / k,
12139               fi = (sinAlpha * dx + cosAlpha * dy) / k;
12140
12141           function transform(x, y) {
12142             x *= sx;
12143             y *= sy;
12144             return [a * x - b * y + dx, dy - b * x - a * y];
12145           }
12146
12147           transform.invert = function (x, y) {
12148             return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)];
12149           };
12150
12151           return transform;
12152         }
12153
12154         function projection(project) {
12155           return projectionMutator(function () {
12156             return project;
12157           })();
12158         }
12159         function projectionMutator(projectAt) {
12160           var project,
12161               k = 150,
12162               // scale
12163           x = 480,
12164               y = 250,
12165               // translate
12166           lambda = 0,
12167               phi = 0,
12168               // center
12169           deltaLambda = 0,
12170               deltaPhi = 0,
12171               deltaGamma = 0,
12172               rotate,
12173               // pre-rotate
12174           alpha = 0,
12175               // post-rotate angle
12176           sx = 1,
12177               // reflectX
12178           sy = 1,
12179               // reflectX
12180           theta = null,
12181               preclip = clipAntimeridian,
12182               // pre-clip angle
12183           x0 = null,
12184               y0,
12185               x1,
12186               y1,
12187               postclip = identity$4,
12188               // post-clip extent
12189           delta2 = 0.5,
12190               // precision
12191           projectResample,
12192               projectTransform,
12193               projectRotateTransform,
12194               cache,
12195               cacheStream;
12196
12197           function projection(point) {
12198             return projectRotateTransform(point[0] * radians, point[1] * radians);
12199           }
12200
12201           function invert(point) {
12202             point = projectRotateTransform.invert(point[0], point[1]);
12203             return point && [point[0] * degrees$1, point[1] * degrees$1];
12204           }
12205
12206           projection.stream = function (stream) {
12207             return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream)))));
12208           };
12209
12210           projection.preclip = function (_) {
12211             return arguments.length ? (preclip = _, theta = undefined, reset()) : preclip;
12212           };
12213
12214           projection.postclip = function (_) {
12215             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12216           };
12217
12218           projection.clipAngle = function (_) {
12219             return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
12220           };
12221
12222           projection.clipExtent = function (_) {
12223             return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
12224           };
12225
12226           projection.scale = function (_) {
12227             return arguments.length ? (k = +_, recenter()) : k;
12228           };
12229
12230           projection.translate = function (_) {
12231             return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
12232           };
12233
12234           projection.center = function (_) {
12235             return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
12236           };
12237
12238           projection.rotate = function (_) {
12239             return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees$1, deltaPhi * degrees$1, deltaGamma * degrees$1];
12240           };
12241
12242           projection.angle = function (_) {
12243             return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees$1;
12244           };
12245
12246           projection.reflectX = function (_) {
12247             return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0;
12248           };
12249
12250           projection.reflectY = function (_) {
12251             return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0;
12252           };
12253
12254           projection.precision = function (_) {
12255             return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
12256           };
12257
12258           projection.fitExtent = function (extent, object) {
12259             return fitExtent(projection, extent, object);
12260           };
12261
12262           projection.fitSize = function (size, object) {
12263             return fitSize(projection, size, object);
12264           };
12265
12266           projection.fitWidth = function (width, object) {
12267             return fitWidth(projection, width, object);
12268           };
12269
12270           projection.fitHeight = function (height, object) {
12271             return fitHeight(projection, height, object);
12272           };
12273
12274           function recenter() {
12275             var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)),
12276                 transform = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha);
12277             rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma);
12278             projectTransform = compose(project, transform);
12279             projectRotateTransform = compose(rotate, projectTransform);
12280             projectResample = resample(projectTransform, delta2);
12281             return reset();
12282           }
12283
12284           function reset() {
12285             cache = cacheStream = null;
12286             return projection;
12287           }
12288
12289           return function () {
12290             project = projectAt.apply(this, arguments);
12291             projection.invert = project.invert && invert;
12292             return recenter();
12293           };
12294         }
12295
12296         function mercatorRaw(lambda, phi) {
12297           return [lambda, log$1(tan((halfPi + phi) / 2))];
12298         }
12299
12300         mercatorRaw.invert = function (x, y) {
12301           return [x, 2 * atan(exp$2(y)) - halfPi];
12302         };
12303
12304         function mercator () {
12305           return mercatorProjection(mercatorRaw).scale(961 / tau);
12306         }
12307         function mercatorProjection(project) {
12308           var m = projection(project),
12309               center = m.center,
12310               scale = m.scale,
12311               translate = m.translate,
12312               clipExtent = m.clipExtent,
12313               x0 = null,
12314               y0,
12315               x1,
12316               y1; // clip extent
12317
12318           m.scale = function (_) {
12319             return arguments.length ? (scale(_), reclip()) : scale();
12320           };
12321
12322           m.translate = function (_) {
12323             return arguments.length ? (translate(_), reclip()) : translate();
12324           };
12325
12326           m.center = function (_) {
12327             return arguments.length ? (center(_), reclip()) : center();
12328           };
12329
12330           m.clipExtent = function (_) {
12331             return arguments.length ? (_ == null ? x0 = y0 = x1 = y1 = null : (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reclip()) : x0 == null ? null : [[x0, y0], [x1, y1]];
12332           };
12333
12334           function reclip() {
12335             var k = pi * scale(),
12336                 t = m(rotation(m.rotate()).invert([0, 0]));
12337             return clipExtent(x0 == null ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]] : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]);
12338           }
12339
12340           return reclip();
12341         }
12342
12343         function d3_geoIdentity () {
12344           var k = 1,
12345               tx = 0,
12346               ty = 0,
12347               sx = 1,
12348               sy = 1,
12349               // scale, translate and reflect
12350           alpha = 0,
12351               ca,
12352               sa,
12353               // angle
12354           x0 = null,
12355               y0,
12356               x1,
12357               y1,
12358               // clip extent
12359           kx = 1,
12360               ky = 1,
12361               transform = transformer$1({
12362             point: function point(x, y) {
12363               var p = projection([x, y]);
12364               this.stream.point(p[0], p[1]);
12365             }
12366           }),
12367               postclip = identity$4,
12368               cache,
12369               cacheStream;
12370
12371           function reset() {
12372             kx = k * sx;
12373             ky = k * sy;
12374             cache = cacheStream = null;
12375             return projection;
12376           }
12377
12378           function projection(p) {
12379             var x = p[0] * kx,
12380                 y = p[1] * ky;
12381
12382             if (alpha) {
12383               var t = y * ca - x * sa;
12384               x = x * ca + y * sa;
12385               y = t;
12386             }
12387
12388             return [x + tx, y + ty];
12389           }
12390
12391           projection.invert = function (p) {
12392             var x = p[0] - tx,
12393                 y = p[1] - ty;
12394
12395             if (alpha) {
12396               var t = y * ca + x * sa;
12397               x = x * ca - y * sa;
12398               y = t;
12399             }
12400
12401             return [x / kx, y / ky];
12402           };
12403
12404           projection.stream = function (stream) {
12405             return cache && cacheStream === stream ? cache : cache = transform(postclip(cacheStream = stream));
12406           };
12407
12408           projection.postclip = function (_) {
12409             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12410           };
12411
12412           projection.clipExtent = function (_) {
12413             return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
12414           };
12415
12416           projection.scale = function (_) {
12417             return arguments.length ? (k = +_, reset()) : k;
12418           };
12419
12420           projection.translate = function (_) {
12421             return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty];
12422           };
12423
12424           projection.angle = function (_) {
12425             return arguments.length ? (alpha = _ % 360 * radians, sa = sin(alpha), ca = cos(alpha), reset()) : alpha * degrees$1;
12426           };
12427
12428           projection.reflectX = function (_) {
12429             return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0;
12430           };
12431
12432           projection.reflectY = function (_) {
12433             return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0;
12434           };
12435
12436           projection.fitExtent = function (extent, object) {
12437             return fitExtent(projection, extent, object);
12438           };
12439
12440           projection.fitSize = function (size, object) {
12441             return fitSize(projection, size, object);
12442           };
12443
12444           projection.fitWidth = function (width, object) {
12445             return fitWidth(projection, width, object);
12446           };
12447
12448           projection.fitHeight = function (height, object) {
12449             return fitHeight(projection, height, object);
12450           };
12451
12452           return projection;
12453         }
12454
12455         // constants
12456         var TAU = 2 * Math.PI;
12457         var EQUATORIAL_RADIUS = 6356752.314245179;
12458         var POLAR_RADIUS$1 = 6378137.0;
12459         function geoLatToMeters(dLat) {
12460           return dLat * (TAU * POLAR_RADIUS$1 / 360);
12461         }
12462         function geoLonToMeters(dLon, atLat) {
12463           return Math.abs(atLat) >= 90 ? 0 : dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180)));
12464         }
12465         function geoMetersToLat(m) {
12466           return m / (TAU * POLAR_RADIUS$1 / 360);
12467         }
12468         function geoMetersToLon(m, atLat) {
12469           return Math.abs(atLat) >= 90 ? 0 : m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
12470         }
12471         function geoMetersToOffset(meters, tileSize) {
12472           tileSize = tileSize || 256;
12473           return [meters[0] * tileSize / (TAU * EQUATORIAL_RADIUS), -meters[1] * tileSize / (TAU * POLAR_RADIUS$1)];
12474         }
12475         function geoOffsetToMeters(offset, tileSize) {
12476           tileSize = tileSize || 256;
12477           return [offset[0] * TAU * EQUATORIAL_RADIUS / tileSize, -offset[1] * TAU * POLAR_RADIUS$1 / tileSize];
12478         } // Equirectangular approximation of spherical distances on Earth
12479
12480         function geoSphericalDistance(a, b) {
12481           var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
12482           var y = geoLatToMeters(a[1] - b[1]);
12483           return Math.sqrt(x * x + y * y);
12484         } // scale to zoom
12485
12486         function geoScaleToZoom(k, tileSize) {
12487           tileSize = tileSize || 256;
12488           var log2ts = Math.log(tileSize) * Math.LOG2E;
12489           return Math.log(k * TAU) / Math.LN2 - log2ts;
12490         } // zoom to scale
12491
12492         function geoZoomToScale(z, tileSize) {
12493           tileSize = tileSize || 256;
12494           return tileSize * Math.pow(2, z) / TAU;
12495         } // returns info about the node from `nodes` closest to the given `point`
12496
12497         function geoSphericalClosestNode(nodes, point) {
12498           var minDistance = Infinity,
12499               distance;
12500           var indexOfMin;
12501
12502           for (var i in nodes) {
12503             distance = geoSphericalDistance(nodes[i].loc, point);
12504
12505             if (distance < minDistance) {
12506               minDistance = distance;
12507               indexOfMin = i;
12508             }
12509           }
12510
12511           if (indexOfMin !== undefined) {
12512             return {
12513               index: indexOfMin,
12514               distance: minDistance,
12515               node: nodes[indexOfMin]
12516             };
12517           } else {
12518             return null;
12519           }
12520         }
12521
12522         function geoExtent(min, max) {
12523           if (!(this instanceof geoExtent)) {
12524             return new geoExtent(min, max);
12525           } else if (min instanceof geoExtent) {
12526             return min;
12527           } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
12528             this[0] = min[0];
12529             this[1] = min[1];
12530           } else {
12531             this[0] = min || [Infinity, Infinity];
12532             this[1] = max || min || [-Infinity, -Infinity];
12533           }
12534         }
12535         geoExtent.prototype = new Array(2);
12536         Object.assign(geoExtent.prototype, {
12537           equals: function equals(obj) {
12538             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];
12539           },
12540           extend: function extend(obj) {
12541             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12542             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])]);
12543           },
12544           _extend: function _extend(extent) {
12545             this[0][0] = Math.min(extent[0][0], this[0][0]);
12546             this[0][1] = Math.min(extent[0][1], this[0][1]);
12547             this[1][0] = Math.max(extent[1][0], this[1][0]);
12548             this[1][1] = Math.max(extent[1][1], this[1][1]);
12549           },
12550           area: function area() {
12551             return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
12552           },
12553           center: function center() {
12554             return [(this[0][0] + this[1][0]) / 2, (this[0][1] + this[1][1]) / 2];
12555           },
12556           rectangle: function rectangle() {
12557             return [this[0][0], this[0][1], this[1][0], this[1][1]];
12558           },
12559           bbox: function bbox() {
12560             return {
12561               minX: this[0][0],
12562               minY: this[0][1],
12563               maxX: this[1][0],
12564               maxY: this[1][1]
12565             };
12566           },
12567           polygon: function polygon() {
12568             return [[this[0][0], this[0][1]], [this[0][0], this[1][1]], [this[1][0], this[1][1]], [this[1][0], this[0][1]], [this[0][0], this[0][1]]];
12569           },
12570           contains: function contains(obj) {
12571             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12572             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];
12573           },
12574           intersects: function intersects(obj) {
12575             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12576             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];
12577           },
12578           intersection: function intersection(obj) {
12579             if (!this.intersects(obj)) return new geoExtent();
12580             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])]);
12581           },
12582           percentContainedIn: function percentContainedIn(obj) {
12583             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12584             var a1 = this.intersection(obj).area();
12585             var a2 = this.area();
12586
12587             if (a1 === Infinity || a2 === Infinity) {
12588               return 0;
12589             } else if (a1 === 0 || a2 === 0) {
12590               if (obj.contains(this)) {
12591                 return 1;
12592               }
12593
12594               return 0;
12595             } else {
12596               return a1 / a2;
12597             }
12598           },
12599           padByMeters: function padByMeters(meters) {
12600             var dLat = geoMetersToLat(meters);
12601             var dLon = geoMetersToLon(meters, this.center()[1]);
12602             return geoExtent([this[0][0] - dLon, this[0][1] - dLat], [this[1][0] + dLon, this[1][1] + dLat]);
12603           },
12604           toParam: function toParam() {
12605             return this.rectangle().join(',');
12606           }
12607         });
12608
12609         var $every = arrayIteration.every;
12610
12611
12612         var STRICT_METHOD$1 = arrayMethodIsStrict('every');
12613
12614         // `Array.prototype.every` method
12615         // https://tc39.es/ecma262/#sec-array.prototype.every
12616         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$1 }, {
12617           every: function every(callbackfn /* , thisArg */) {
12618             return $every(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
12619           }
12620         });
12621
12622         var $reduce = arrayReduce.left;
12623
12624
12625
12626
12627         var STRICT_METHOD = arrayMethodIsStrict('reduce');
12628         // Chrome 80-82 has a critical bug
12629         // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
12630         var CHROME_BUG = !engineIsNode && engineV8Version > 79 && engineV8Version < 83;
12631
12632         // `Array.prototype.reduce` method
12633         // https://tc39.es/ecma262/#sec-array.prototype.reduce
12634         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD || CHROME_BUG }, {
12635           reduce: function reduce(callbackfn /* , initialValue */) {
12636             return $reduce(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
12637           }
12638         });
12639
12640         function d3_polygonArea (polygon) {
12641           var i = -1,
12642               n = polygon.length,
12643               a,
12644               b = polygon[n - 1],
12645               area = 0;
12646
12647           while (++i < n) {
12648             a = b;
12649             b = polygon[i];
12650             area += a[1] * b[0] - a[0] * b[1];
12651           }
12652
12653           return area / 2;
12654         }
12655
12656         function d3_polygonCentroid (polygon) {
12657           var i = -1,
12658               n = polygon.length,
12659               x = 0,
12660               y = 0,
12661               a,
12662               b = polygon[n - 1],
12663               c,
12664               k = 0;
12665
12666           while (++i < n) {
12667             a = b;
12668             b = polygon[i];
12669             k += c = a[0] * b[1] - b[0] * a[1];
12670             x += (a[0] + b[0]) * c;
12671             y += (a[1] + b[1]) * c;
12672           }
12673
12674           return k *= 3, [x / k, y / k];
12675         }
12676
12677         // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
12678         // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
12679         // right, +y is up). Returns a positive value if ABC is counter-clockwise,
12680         // negative if clockwise, and zero if the points are collinear.
12681         function cross (a, b, c) {
12682           return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
12683         }
12684
12685         function lexicographicOrder(a, b) {
12686           return a[0] - b[0] || a[1] - b[1];
12687         } // Computes the upper convex hull per the monotone chain algorithm.
12688         // Assumes points.length >= 3, is sorted by x, unique in y.
12689         // Returns an array of indices into points in left-to-right order.
12690
12691
12692         function computeUpperHullIndexes(points) {
12693           var n = points.length,
12694               indexes = [0, 1];
12695           var size = 2,
12696               i;
12697
12698           for (i = 2; i < n; ++i) {
12699             while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) {
12700               --size;
12701             }
12702
12703             indexes[size++] = i;
12704           }
12705
12706           return indexes.slice(0, size); // remove popped points
12707         }
12708
12709         function d3_polygonHull (points) {
12710           if ((n = points.length) < 3) return null;
12711           var i,
12712               n,
12713               sortedPoints = new Array(n),
12714               flippedPoints = new Array(n);
12715
12716           for (i = 0; i < n; ++i) {
12717             sortedPoints[i] = [+points[i][0], +points[i][1], i];
12718           }
12719
12720           sortedPoints.sort(lexicographicOrder);
12721
12722           for (i = 0; i < n; ++i) {
12723             flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
12724           }
12725
12726           var upperIndexes = computeUpperHullIndexes(sortedPoints),
12727               lowerIndexes = computeUpperHullIndexes(flippedPoints); // Construct the hull polygon, removing possible duplicate endpoints.
12728
12729           var skipLeft = lowerIndexes[0] === upperIndexes[0],
12730               skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
12731               hull = []; // Add upper hull in right-to-l order.
12732           // Then add lower hull in left-to-right order.
12733
12734           for (i = upperIndexes.length - 1; i >= 0; --i) {
12735             hull.push(points[sortedPoints[upperIndexes[i]][2]]);
12736           }
12737
12738           for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) {
12739             hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
12740           }
12741
12742           return hull;
12743         }
12744
12745         // vector equals
12746         function geoVecEqual(a, b, epsilon) {
12747           if (epsilon) {
12748             return Math.abs(a[0] - b[0]) <= epsilon && Math.abs(a[1] - b[1]) <= epsilon;
12749           } else {
12750             return a[0] === b[0] && a[1] === b[1];
12751           }
12752         } // vector addition
12753
12754         function geoVecAdd(a, b) {
12755           return [a[0] + b[0], a[1] + b[1]];
12756         } // vector subtraction
12757
12758         function geoVecSubtract(a, b) {
12759           return [a[0] - b[0], a[1] - b[1]];
12760         } // vector scaling
12761
12762         function geoVecScale(a, mag) {
12763           return [a[0] * mag, a[1] * mag];
12764         } // vector rounding (was: geoRoundCoordinates)
12765
12766         function geoVecFloor(a) {
12767           return [Math.floor(a[0]), Math.floor(a[1])];
12768         } // linear interpolation
12769
12770         function geoVecInterp(a, b, t) {
12771           return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
12772         } // http://jsperf.com/id-dist-optimization
12773
12774         function geoVecLength(a, b) {
12775           return Math.sqrt(geoVecLengthSquare(a, b));
12776         } // length of vector raised to the power two
12777
12778         function geoVecLengthSquare(a, b) {
12779           b = b || [0, 0];
12780           var x = a[0] - b[0];
12781           var y = a[1] - b[1];
12782           return x * x + y * y;
12783         } // get a unit vector
12784
12785         function geoVecNormalize(a) {
12786           var length = Math.sqrt(a[0] * a[0] + a[1] * a[1]);
12787
12788           if (length !== 0) {
12789             return geoVecScale(a, 1 / length);
12790           }
12791
12792           return [0, 0];
12793         } // Return the counterclockwise angle in the range (-pi, pi)
12794         // between the positive X axis and the line intersecting a and b.
12795
12796         function geoVecAngle(a, b) {
12797           return Math.atan2(b[1] - a[1], b[0] - a[0]);
12798         } // dot product
12799
12800         function geoVecDot(a, b, origin) {
12801           origin = origin || [0, 0];
12802           var p = geoVecSubtract(a, origin);
12803           var q = geoVecSubtract(b, origin);
12804           return p[0] * q[0] + p[1] * q[1];
12805         } // normalized dot product
12806
12807         function geoVecNormalizedDot(a, b, origin) {
12808           origin = origin || [0, 0];
12809           var p = geoVecNormalize(geoVecSubtract(a, origin));
12810           var q = geoVecNormalize(geoVecSubtract(b, origin));
12811           return geoVecDot(p, q);
12812         } // 2D cross product of OA and OB vectors, returns magnitude of Z vector
12813         // Returns a positive value, if OAB makes a counter-clockwise turn,
12814         // negative for clockwise turn, and zero if the points are collinear.
12815
12816         function geoVecCross(a, b, origin) {
12817           origin = origin || [0, 0];
12818           var p = geoVecSubtract(a, origin);
12819           var q = geoVecSubtract(b, origin);
12820           return p[0] * q[1] - p[1] * q[0];
12821         } // find closest orthogonal projection of point onto points array
12822
12823         function geoVecProject(a, points) {
12824           var min = Infinity;
12825           var idx;
12826           var target;
12827
12828           for (var i = 0; i < points.length - 1; i++) {
12829             var o = points[i];
12830             var s = geoVecSubtract(points[i + 1], o);
12831             var v = geoVecSubtract(a, o);
12832             var proj = geoVecDot(v, s) / geoVecDot(s, s);
12833             var p;
12834
12835             if (proj < 0) {
12836               p = o;
12837             } else if (proj > 1) {
12838               p = points[i + 1];
12839             } else {
12840               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
12841             }
12842
12843             var dist = geoVecLength(p, a);
12844
12845             if (dist < min) {
12846               min = dist;
12847               idx = i + 1;
12848               target = p;
12849             }
12850           }
12851
12852           if (idx !== undefined) {
12853             return {
12854               index: idx,
12855               distance: min,
12856               target: target
12857             };
12858           } else {
12859             return null;
12860           }
12861         }
12862
12863         // between the positive X axis and the line intersecting a and b.
12864
12865         function geoAngle(a, b, projection) {
12866           return geoVecAngle(projection(a.loc), projection(b.loc));
12867         }
12868         function geoEdgeEqual(a, b) {
12869           return a[0] === b[0] && a[1] === b[1] || a[0] === b[1] && a[1] === b[0];
12870         } // Rotate all points counterclockwise around a pivot point by given angle
12871
12872         function geoRotate(points, angle, around) {
12873           return points.map(function (point) {
12874             var radial = geoVecSubtract(point, around);
12875             return [radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + around[0], radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + around[1]];
12876           });
12877         } // Choose the edge with the minimal distance from `point` to its orthogonal
12878         // projection onto that edge, if such a projection exists, or the distance to
12879         // the closest vertex on that edge. Returns an object with the `index` of the
12880         // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
12881
12882         function geoChooseEdge(nodes, point, projection, activeID) {
12883           var dist = geoVecLength;
12884           var points = nodes.map(function (n) {
12885             return projection(n.loc);
12886           });
12887           var ids = nodes.map(function (n) {
12888             return n.id;
12889           });
12890           var min = Infinity;
12891           var idx;
12892           var loc;
12893
12894           for (var i = 0; i < points.length - 1; i++) {
12895             if (ids[i] === activeID || ids[i + 1] === activeID) continue;
12896             var o = points[i];
12897             var s = geoVecSubtract(points[i + 1], o);
12898             var v = geoVecSubtract(point, o);
12899             var proj = geoVecDot(v, s) / geoVecDot(s, s);
12900             var p;
12901
12902             if (proj < 0) {
12903               p = o;
12904             } else if (proj > 1) {
12905               p = points[i + 1];
12906             } else {
12907               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
12908             }
12909
12910             var d = dist(p, point);
12911
12912             if (d < min) {
12913               min = d;
12914               idx = i + 1;
12915               loc = projection.invert(p);
12916             }
12917           }
12918
12919           if (idx !== undefined) {
12920             return {
12921               index: idx,
12922               distance: min,
12923               loc: loc
12924             };
12925           } else {
12926             return null;
12927           }
12928         } // Test active (dragged or drawing) segments against inactive segments
12929         // This is used to test e.g. multipolygon rings that cross
12930         // `activeNodes` is the ring containing the activeID being dragged.
12931         // `inactiveNodes` is the other ring to test against
12932
12933         function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
12934           var actives = [];
12935           var inactives = [];
12936           var j, k, n1, n2, segment; // gather active segments (only segments in activeNodes that contain the activeID)
12937
12938           for (j = 0; j < activeNodes.length - 1; j++) {
12939             n1 = activeNodes[j];
12940             n2 = activeNodes[j + 1];
12941             segment = [n1.loc, n2.loc];
12942
12943             if (n1.id === activeID || n2.id === activeID) {
12944               actives.push(segment);
12945             }
12946           } // gather inactive segments
12947
12948
12949           for (j = 0; j < inactiveNodes.length - 1; j++) {
12950             n1 = inactiveNodes[j];
12951             n2 = inactiveNodes[j + 1];
12952             segment = [n1.loc, n2.loc];
12953             inactives.push(segment);
12954           } // test
12955
12956
12957           for (j = 0; j < actives.length; j++) {
12958             for (k = 0; k < inactives.length; k++) {
12959               var p = actives[j];
12960               var q = inactives[k];
12961               var hit = geoLineIntersection(p, q);
12962
12963               if (hit) {
12964                 return true;
12965               }
12966             }
12967           }
12968
12969           return false;
12970         } // Test active (dragged or drawing) segments against inactive segments
12971         // This is used to test whether a way intersects with itself.
12972
12973         function geoHasSelfIntersections(nodes, activeID) {
12974           var actives = [];
12975           var inactives = [];
12976           var j, k; // group active and passive segments along the nodes
12977
12978           for (j = 0; j < nodes.length - 1; j++) {
12979             var n1 = nodes[j];
12980             var n2 = nodes[j + 1];
12981             var segment = [n1.loc, n2.loc];
12982
12983             if (n1.id === activeID || n2.id === activeID) {
12984               actives.push(segment);
12985             } else {
12986               inactives.push(segment);
12987             }
12988           } // test
12989
12990
12991           for (j = 0; j < actives.length; j++) {
12992             for (k = 0; k < inactives.length; k++) {
12993               var p = actives[j];
12994               var q = inactives[k]; // skip if segments share an endpoint
12995
12996               if (geoVecEqual(p[1], q[0]) || geoVecEqual(p[0], q[1]) || geoVecEqual(p[0], q[0]) || geoVecEqual(p[1], q[1])) {
12997                 continue;
12998               }
12999
13000               var hit = geoLineIntersection(p, q);
13001
13002               if (hit) {
13003                 var epsilon = 1e-8; // skip if the hit is at the segment's endpoint
13004
13005                 if (geoVecEqual(p[1], hit, epsilon) || geoVecEqual(p[0], hit, epsilon) || geoVecEqual(q[1], hit, epsilon) || geoVecEqual(q[0], hit, epsilon)) {
13006                   continue;
13007                 } else {
13008                   return true;
13009                 }
13010               }
13011             }
13012           }
13013
13014           return false;
13015         } // Return the intersection point of 2 line segments.
13016         // From https://github.com/pgkelley4/line-segments-intersect
13017         // This uses the vector cross product approach described below:
13018         //  http://stackoverflow.com/a/565282/786339
13019
13020         function geoLineIntersection(a, b) {
13021           var p = [a[0][0], a[0][1]];
13022           var p2 = [a[1][0], a[1][1]];
13023           var q = [b[0][0], b[0][1]];
13024           var q2 = [b[1][0], b[1][1]];
13025           var r = geoVecSubtract(p2, p);
13026           var s = geoVecSubtract(q2, q);
13027           var uNumerator = geoVecCross(geoVecSubtract(q, p), r);
13028           var denominator = geoVecCross(r, s);
13029
13030           if (uNumerator && denominator) {
13031             var u = uNumerator / denominator;
13032             var t = geoVecCross(geoVecSubtract(q, p), s) / denominator;
13033
13034             if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
13035               return geoVecInterp(p, p2, t);
13036             }
13037           }
13038
13039           return null;
13040         }
13041         function geoPathIntersections(path1, path2) {
13042           var intersections = [];
13043
13044           for (var i = 0; i < path1.length - 1; i++) {
13045             for (var j = 0; j < path2.length - 1; j++) {
13046               var a = [path1[i], path1[i + 1]];
13047               var b = [path2[j], path2[j + 1]];
13048               var hit = geoLineIntersection(a, b);
13049
13050               if (hit) {
13051                 intersections.push(hit);
13052               }
13053             }
13054           }
13055
13056           return intersections;
13057         }
13058         function geoPathHasIntersections(path1, path2) {
13059           for (var i = 0; i < path1.length - 1; i++) {
13060             for (var j = 0; j < path2.length - 1; j++) {
13061               var a = [path1[i], path1[i + 1]];
13062               var b = [path2[j], path2[j + 1]];
13063               var hit = geoLineIntersection(a, b);
13064
13065               if (hit) {
13066                 return true;
13067               }
13068             }
13069           }
13070
13071           return false;
13072         } // Return whether point is contained in polygon.
13073         //
13074         // `point` should be a 2-item array of coordinates.
13075         // `polygon` should be an array of 2-item arrays of coordinates.
13076         //
13077         // From https://github.com/substack/point-in-polygon.
13078         // ray-casting algorithm based on
13079         // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
13080         //
13081
13082         function geoPointInPolygon(point, polygon) {
13083           var x = point[0];
13084           var y = point[1];
13085           var inside = false;
13086
13087           for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
13088             var xi = polygon[i][0];
13089             var yi = polygon[i][1];
13090             var xj = polygon[j][0];
13091             var yj = polygon[j][1];
13092             var intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
13093             if (intersect) inside = !inside;
13094           }
13095
13096           return inside;
13097         }
13098         function geoPolygonContainsPolygon(outer, inner) {
13099           return inner.every(function (point) {
13100             return geoPointInPolygon(point, outer);
13101           });
13102         }
13103         function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
13104           function testPoints(outer, inner) {
13105             return inner.some(function (point) {
13106               return geoPointInPolygon(point, outer);
13107             });
13108           }
13109
13110           return testPoints(outer, inner) || !!checkSegments && geoPathHasIntersections(outer, inner);
13111         } // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
13112         // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
13113
13114         function geoGetSmallestSurroundingRectangle(points) {
13115           var hull = d3_polygonHull(points);
13116           var centroid = d3_polygonCentroid(hull);
13117           var minArea = Infinity;
13118           var ssrExtent = [];
13119           var ssrAngle = 0;
13120           var c1 = hull[0];
13121
13122           for (var i = 0; i <= hull.length - 1; i++) {
13123             var c2 = i === hull.length - 1 ? hull[0] : hull[i + 1];
13124             var angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]);
13125             var poly = geoRotate(hull, -angle, centroid);
13126             var extent = poly.reduce(function (extent, point) {
13127               return extent.extend(geoExtent(point));
13128             }, geoExtent());
13129             var area = extent.area();
13130
13131             if (area < minArea) {
13132               minArea = area;
13133               ssrExtent = extent;
13134               ssrAngle = angle;
13135             }
13136
13137             c1 = c2;
13138           }
13139
13140           return {
13141             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
13142             angle: ssrAngle
13143           };
13144         }
13145         function geoPathLength(path) {
13146           var length = 0;
13147
13148           for (var i = 0; i < path.length - 1; i++) {
13149             length += geoVecLength(path[i], path[i + 1]);
13150           }
13151
13152           return length;
13153         } // If the given point is at the edge of the padded viewport,
13154         // return a vector that will nudge the viewport in that direction
13155
13156         function geoViewportEdge(point, dimensions) {
13157           var pad = [80, 20, 50, 20]; // top, right, bottom, left
13158
13159           var x = 0;
13160           var y = 0;
13161
13162           if (point[0] > dimensions[0] - pad[1]) {
13163             x = -10;
13164           }
13165
13166           if (point[0] < pad[3]) {
13167             x = 10;
13168           }
13169
13170           if (point[1] > dimensions[1] - pad[2]) {
13171             y = -10;
13172           }
13173
13174           if (point[1] < pad[0]) {
13175             y = 10;
13176           }
13177
13178           if (x || y) {
13179             return [x, y];
13180           } else {
13181             return null;
13182           }
13183         }
13184
13185         var noop = {
13186           value: function value() {}
13187         };
13188
13189         function dispatch$8() {
13190           for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
13191             if (!(t = arguments[i] + "") || t in _ || /[\s.]/.test(t)) throw new Error("illegal type: " + t);
13192             _[t] = [];
13193           }
13194
13195           return new Dispatch(_);
13196         }
13197
13198         function Dispatch(_) {
13199           this._ = _;
13200         }
13201
13202         function parseTypenames$1(typenames, types) {
13203           return typenames.trim().split(/^|\s+/).map(function (t) {
13204             var name = "",
13205                 i = t.indexOf(".");
13206             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
13207             if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
13208             return {
13209               type: t,
13210               name: name
13211             };
13212           });
13213         }
13214
13215         Dispatch.prototype = dispatch$8.prototype = {
13216           constructor: Dispatch,
13217           on: function on(typename, callback) {
13218             var _ = this._,
13219                 T = parseTypenames$1(typename + "", _),
13220                 t,
13221                 i = -1,
13222                 n = T.length; // If no callback was specified, return the callback of the given type and name.
13223
13224             if (arguments.length < 2) {
13225               while (++i < n) {
13226                 if ((t = (typename = T[i]).type) && (t = get$2(_[t], typename.name))) return t;
13227               }
13228
13229               return;
13230             } // If a type was specified, set the callback for the given type and name.
13231             // Otherwise, if a null callback was specified, remove callbacks of the given name.
13232
13233
13234             if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
13235
13236             while (++i < n) {
13237               if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback);else if (callback == null) for (t in _) {
13238                 _[t] = set$1(_[t], typename.name, null);
13239               }
13240             }
13241
13242             return this;
13243           },
13244           copy: function copy() {
13245             var copy = {},
13246                 _ = this._;
13247
13248             for (var t in _) {
13249               copy[t] = _[t].slice();
13250             }
13251
13252             return new Dispatch(copy);
13253           },
13254           call: function call(type, that) {
13255             if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) {
13256               args[i] = arguments[i + 2];
13257             }
13258             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13259
13260             for (t = this._[type], i = 0, n = t.length; i < n; ++i) {
13261               t[i].value.apply(that, args);
13262             }
13263           },
13264           apply: function apply(type, that, args) {
13265             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13266
13267             for (var t = this._[type], i = 0, n = t.length; i < n; ++i) {
13268               t[i].value.apply(that, args);
13269             }
13270           }
13271         };
13272
13273         function get$2(type, name) {
13274           for (var i = 0, n = type.length, c; i < n; ++i) {
13275             if ((c = type[i]).name === name) {
13276               return c.value;
13277             }
13278           }
13279         }
13280
13281         function set$1(type, name, callback) {
13282           for (var i = 0, n = type.length; i < n; ++i) {
13283             if (type[i].name === name) {
13284               type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
13285               break;
13286             }
13287           }
13288
13289           if (callback != null) type.push({
13290             name: name,
13291             value: callback
13292           });
13293           return type;
13294         }
13295
13296         var xhtml = "http://www.w3.org/1999/xhtml";
13297         var namespaces = {
13298           svg: "http://www.w3.org/2000/svg",
13299           xhtml: xhtml,
13300           xlink: "http://www.w3.org/1999/xlink",
13301           xml: "http://www.w3.org/XML/1998/namespace",
13302           xmlns: "http://www.w3.org/2000/xmlns/"
13303         };
13304
13305         function namespace (name) {
13306           var prefix = name += "",
13307               i = prefix.indexOf(":");
13308           if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
13309           return namespaces.hasOwnProperty(prefix) ? {
13310             space: namespaces[prefix],
13311             local: name
13312           } : name; // eslint-disable-line no-prototype-builtins
13313         }
13314
13315         function creatorInherit(name) {
13316           return function () {
13317             var document = this.ownerDocument,
13318                 uri = this.namespaceURI;
13319             return uri === xhtml && document.documentElement.namespaceURI === xhtml ? document.createElement(name) : document.createElementNS(uri, name);
13320           };
13321         }
13322
13323         function creatorFixed(fullname) {
13324           return function () {
13325             return this.ownerDocument.createElementNS(fullname.space, fullname.local);
13326           };
13327         }
13328
13329         function creator (name) {
13330           var fullname = namespace(name);
13331           return (fullname.local ? creatorFixed : creatorInherit)(fullname);
13332         }
13333
13334         function none() {}
13335
13336         function selector (selector) {
13337           return selector == null ? none : function () {
13338             return this.querySelector(selector);
13339           };
13340         }
13341
13342         function selection_select (select) {
13343           if (typeof select !== "function") select = selector(select);
13344
13345           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
13346             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
13347               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
13348                 if ("__data__" in node) subnode.__data__ = node.__data__;
13349                 subgroup[i] = subnode;
13350               }
13351             }
13352           }
13353
13354           return new Selection$1(subgroups, this._parents);
13355         }
13356
13357         function array (x) {
13358           return _typeof(x) === "object" && "length" in x ? x // Array, TypedArray, NodeList, array-like
13359           : Array.from(x); // Map, Set, iterable, string, or anything else
13360         }
13361
13362         function empty() {
13363           return [];
13364         }
13365
13366         function selectorAll (selector) {
13367           return selector == null ? empty : function () {
13368             return this.querySelectorAll(selector);
13369           };
13370         }
13371
13372         function arrayAll(select) {
13373           return function () {
13374             var group = select.apply(this, arguments);
13375             return group == null ? [] : array(group);
13376           };
13377         }
13378
13379         function selection_selectAll (select) {
13380           if (typeof select === "function") select = arrayAll(select);else select = selectorAll(select);
13381
13382           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
13383             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
13384               if (node = group[i]) {
13385                 subgroups.push(select.call(node, node.__data__, i, group));
13386                 parents.push(node);
13387               }
13388             }
13389           }
13390
13391           return new Selection$1(subgroups, parents);
13392         }
13393
13394         var $find = arrayIteration.find;
13395
13396
13397         var FIND = 'find';
13398         var SKIPS_HOLES$1 = true;
13399
13400         // Shouldn't skip holes
13401         if (FIND in []) Array(1)[FIND](function () { SKIPS_HOLES$1 = false; });
13402
13403         // `Array.prototype.find` method
13404         // https://tc39.es/ecma262/#sec-array.prototype.find
13405         _export({ target: 'Array', proto: true, forced: SKIPS_HOLES$1 }, {
13406           find: function find(callbackfn /* , that = undefined */) {
13407             return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
13408           }
13409         });
13410
13411         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
13412         addToUnscopables(FIND);
13413
13414         function matcher (selector) {
13415           return function () {
13416             return this.matches(selector);
13417           };
13418         }
13419         function childMatcher(selector) {
13420           return function (node) {
13421             return node.matches(selector);
13422           };
13423         }
13424
13425         var find = Array.prototype.find;
13426
13427         function childFind(match) {
13428           return function () {
13429             return find.call(this.children, match);
13430           };
13431         }
13432
13433         function childFirst() {
13434           return this.firstElementChild;
13435         }
13436
13437         function selection_selectChild (match) {
13438           return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
13439         }
13440
13441         var filter = Array.prototype.filter;
13442
13443         function children() {
13444           return this.children;
13445         }
13446
13447         function childrenFilter(match) {
13448           return function () {
13449             return filter.call(this.children, match);
13450           };
13451         }
13452
13453         function selection_selectChildren (match) {
13454           return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
13455         }
13456
13457         function selection_filter (match) {
13458           if (typeof match !== "function") match = matcher(match);
13459
13460           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
13461             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
13462               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
13463                 subgroup.push(node);
13464               }
13465             }
13466           }
13467
13468           return new Selection$1(subgroups, this._parents);
13469         }
13470
13471         function sparse (update) {
13472           return new Array(update.length);
13473         }
13474
13475         function selection_enter () {
13476           return new Selection$1(this._enter || this._groups.map(sparse), this._parents);
13477         }
13478         function EnterNode(parent, datum) {
13479           this.ownerDocument = parent.ownerDocument;
13480           this.namespaceURI = parent.namespaceURI;
13481           this._next = null;
13482           this._parent = parent;
13483           this.__data__ = datum;
13484         }
13485         EnterNode.prototype = {
13486           constructor: EnterNode,
13487           appendChild: function appendChild(child) {
13488             return this._parent.insertBefore(child, this._next);
13489           },
13490           insertBefore: function insertBefore(child, next) {
13491             return this._parent.insertBefore(child, next);
13492           },
13493           querySelector: function querySelector(selector) {
13494             return this._parent.querySelector(selector);
13495           },
13496           querySelectorAll: function querySelectorAll(selector) {
13497             return this._parent.querySelectorAll(selector);
13498           }
13499         };
13500
13501         function constant$3 (x) {
13502           return function () {
13503             return x;
13504           };
13505         }
13506
13507         function bindIndex(parent, group, enter, update, exit, data) {
13508           var i = 0,
13509               node,
13510               groupLength = group.length,
13511               dataLength = data.length; // Put any non-null nodes that fit into update.
13512           // Put any null nodes into enter.
13513           // Put any remaining data into enter.
13514
13515           for (; i < dataLength; ++i) {
13516             if (node = group[i]) {
13517               node.__data__ = data[i];
13518               update[i] = node;
13519             } else {
13520               enter[i] = new EnterNode(parent, data[i]);
13521             }
13522           } // Put any non-null nodes that don’t fit into exit.
13523
13524
13525           for (; i < groupLength; ++i) {
13526             if (node = group[i]) {
13527               exit[i] = node;
13528             }
13529           }
13530         }
13531
13532         function bindKey(parent, group, enter, update, exit, data, key) {
13533           var i,
13534               node,
13535               nodeByKeyValue = new Map(),
13536               groupLength = group.length,
13537               dataLength = data.length,
13538               keyValues = new Array(groupLength),
13539               keyValue; // Compute the key for each node.
13540           // If multiple nodes have the same key, the duplicates are added to exit.
13541
13542           for (i = 0; i < groupLength; ++i) {
13543             if (node = group[i]) {
13544               keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
13545
13546               if (nodeByKeyValue.has(keyValue)) {
13547                 exit[i] = node;
13548               } else {
13549                 nodeByKeyValue.set(keyValue, node);
13550               }
13551             }
13552           } // Compute the key for each datum.
13553           // If there a node associated with this key, join and add it to update.
13554           // If there is not (or the key is a duplicate), add it to enter.
13555
13556
13557           for (i = 0; i < dataLength; ++i) {
13558             keyValue = key.call(parent, data[i], i, data) + "";
13559
13560             if (node = nodeByKeyValue.get(keyValue)) {
13561               update[i] = node;
13562               node.__data__ = data[i];
13563               nodeByKeyValue["delete"](keyValue);
13564             } else {
13565               enter[i] = new EnterNode(parent, data[i]);
13566             }
13567           } // Add any remaining nodes that were not bound to data to exit.
13568
13569
13570           for (i = 0; i < groupLength; ++i) {
13571             if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) {
13572               exit[i] = node;
13573             }
13574           }
13575         }
13576
13577         function datum(node) {
13578           return node.__data__;
13579         }
13580
13581         function selection_data (value, key) {
13582           if (!arguments.length) return Array.from(this, datum);
13583           var bind = key ? bindKey : bindIndex,
13584               parents = this._parents,
13585               groups = this._groups;
13586           if (typeof value !== "function") value = constant$3(value);
13587
13588           for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
13589             var parent = parents[j],
13590                 group = groups[j],
13591                 groupLength = group.length,
13592                 data = array(value.call(parent, parent && parent.__data__, j, parents)),
13593                 dataLength = data.length,
13594                 enterGroup = enter[j] = new Array(dataLength),
13595                 updateGroup = update[j] = new Array(dataLength),
13596                 exitGroup = exit[j] = new Array(groupLength);
13597             bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); // Now connect the enter nodes to their following update node, such that
13598             // appendChild can insert the materialized enter node before this node,
13599             // rather than at the end of the parent node.
13600
13601             for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
13602               if (previous = enterGroup[i0]) {
13603                 if (i0 >= i1) i1 = i0 + 1;
13604
13605                 while (!(next = updateGroup[i1]) && ++i1 < dataLength) {
13606                 }
13607
13608                 previous._next = next || null;
13609               }
13610             }
13611           }
13612
13613           update = new Selection$1(update, parents);
13614           update._enter = enter;
13615           update._exit = exit;
13616           return update;
13617         }
13618
13619         function selection_exit () {
13620           return new Selection$1(this._exit || this._groups.map(sparse), this._parents);
13621         }
13622
13623         function selection_join (onenter, onupdate, onexit) {
13624           var enter = this.enter(),
13625               update = this,
13626               exit = this.exit();
13627           enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
13628           if (onupdate != null) update = onupdate(update);
13629           if (onexit == null) exit.remove();else onexit(exit);
13630           return enter && update ? enter.merge(update).order() : update;
13631         }
13632
13633         function selection_merge (selection) {
13634           if (!(selection instanceof Selection$1)) throw new Error("invalid merge");
13635
13636           for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
13637             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
13638               if (node = group0[i] || group1[i]) {
13639                 merge[i] = node;
13640               }
13641             }
13642           }
13643
13644           for (; j < m0; ++j) {
13645             merges[j] = groups0[j];
13646           }
13647
13648           return new Selection$1(merges, this._parents);
13649         }
13650
13651         function selection_order () {
13652           for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
13653             for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
13654               if (node = group[i]) {
13655                 if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
13656                 next = node;
13657               }
13658             }
13659           }
13660
13661           return this;
13662         }
13663
13664         function selection_sort (compare) {
13665           if (!compare) compare = ascending;
13666
13667           function compareNode(a, b) {
13668             return a && b ? compare(a.__data__, b.__data__) : !a - !b;
13669           }
13670
13671           for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
13672             for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
13673               if (node = group[i]) {
13674                 sortgroup[i] = node;
13675               }
13676             }
13677
13678             sortgroup.sort(compareNode);
13679           }
13680
13681           return new Selection$1(sortgroups, this._parents).order();
13682         }
13683
13684         function ascending(a, b) {
13685           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
13686         }
13687
13688         function selection_call () {
13689           var callback = arguments[0];
13690           arguments[0] = this;
13691           callback.apply(null, arguments);
13692           return this;
13693         }
13694
13695         function selection_nodes () {
13696           return Array.from(this);
13697         }
13698
13699         function selection_node () {
13700           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
13701             for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
13702               var node = group[i];
13703               if (node) return node;
13704             }
13705           }
13706
13707           return null;
13708         }
13709
13710         function selection_size () {
13711           var size = 0;
13712
13713           var _iterator = _createForOfIteratorHelper(this),
13714               _step;
13715
13716           try {
13717             for (_iterator.s(); !(_step = _iterator.n()).done;) {
13718               var node = _step.value;
13719               ++size;
13720             } // eslint-disable-line no-unused-vars
13721
13722           } catch (err) {
13723             _iterator.e(err);
13724           } finally {
13725             _iterator.f();
13726           }
13727
13728           return size;
13729         }
13730
13731         function selection_empty () {
13732           return !this.node();
13733         }
13734
13735         function selection_each (callback) {
13736           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
13737             for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
13738               if (node = group[i]) callback.call(node, node.__data__, i, group);
13739             }
13740           }
13741
13742           return this;
13743         }
13744
13745         function attrRemove$1(name) {
13746           return function () {
13747             this.removeAttribute(name);
13748           };
13749         }
13750
13751         function attrRemoveNS$1(fullname) {
13752           return function () {
13753             this.removeAttributeNS(fullname.space, fullname.local);
13754           };
13755         }
13756
13757         function attrConstant$1(name, value) {
13758           return function () {
13759             this.setAttribute(name, value);
13760           };
13761         }
13762
13763         function attrConstantNS$1(fullname, value) {
13764           return function () {
13765             this.setAttributeNS(fullname.space, fullname.local, value);
13766           };
13767         }
13768
13769         function attrFunction$1(name, value) {
13770           return function () {
13771             var v = value.apply(this, arguments);
13772             if (v == null) this.removeAttribute(name);else this.setAttribute(name, v);
13773           };
13774         }
13775
13776         function attrFunctionNS$1(fullname, value) {
13777           return function () {
13778             var v = value.apply(this, arguments);
13779             if (v == null) this.removeAttributeNS(fullname.space, fullname.local);else this.setAttributeNS(fullname.space, fullname.local, v);
13780           };
13781         }
13782
13783         function selection_attr (name, value) {
13784           var fullname = namespace(name);
13785
13786           if (arguments.length < 2) {
13787             var node = this.node();
13788             return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
13789           }
13790
13791           return this.each((value == null ? fullname.local ? attrRemoveNS$1 : attrRemove$1 : typeof value === "function" ? fullname.local ? attrFunctionNS$1 : attrFunction$1 : fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, value));
13792         }
13793
13794         function defaultView (node) {
13795           return node.ownerDocument && node.ownerDocument.defaultView || // node is a Node
13796           node.document && node // node is a Window
13797           || node.defaultView; // node is a Document
13798         }
13799
13800         function styleRemove$1(name) {
13801           return function () {
13802             this.style.removeProperty(name);
13803           };
13804         }
13805
13806         function styleConstant$1(name, value, priority) {
13807           return function () {
13808             this.style.setProperty(name, value, priority);
13809           };
13810         }
13811
13812         function styleFunction$1(name, value, priority) {
13813           return function () {
13814             var v = value.apply(this, arguments);
13815             if (v == null) this.style.removeProperty(name);else this.style.setProperty(name, v, priority);
13816           };
13817         }
13818
13819         function selection_style (name, value, priority) {
13820           return arguments.length > 1 ? this.each((value == null ? styleRemove$1 : typeof value === "function" ? styleFunction$1 : styleConstant$1)(name, value, priority == null ? "" : priority)) : styleValue(this.node(), name);
13821         }
13822         function styleValue(node, name) {
13823           return node.style.getPropertyValue(name) || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
13824         }
13825
13826         function propertyRemove(name) {
13827           return function () {
13828             delete this[name];
13829           };
13830         }
13831
13832         function propertyConstant(name, value) {
13833           return function () {
13834             this[name] = value;
13835           };
13836         }
13837
13838         function propertyFunction(name, value) {
13839           return function () {
13840             var v = value.apply(this, arguments);
13841             if (v == null) delete this[name];else this[name] = v;
13842           };
13843         }
13844
13845         function selection_property (name, value) {
13846           return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
13847         }
13848
13849         function classArray(string) {
13850           return string.trim().split(/^|\s+/);
13851         }
13852
13853         function classList(node) {
13854           return node.classList || new ClassList(node);
13855         }
13856
13857         function ClassList(node) {
13858           this._node = node;
13859           this._names = classArray(node.getAttribute("class") || "");
13860         }
13861
13862         ClassList.prototype = {
13863           add: function add(name) {
13864             var i = this._names.indexOf(name);
13865
13866             if (i < 0) {
13867               this._names.push(name);
13868
13869               this._node.setAttribute("class", this._names.join(" "));
13870             }
13871           },
13872           remove: function remove(name) {
13873             var i = this._names.indexOf(name);
13874
13875             if (i >= 0) {
13876               this._names.splice(i, 1);
13877
13878               this._node.setAttribute("class", this._names.join(" "));
13879             }
13880           },
13881           contains: function contains(name) {
13882             return this._names.indexOf(name) >= 0;
13883           }
13884         };
13885
13886         function classedAdd(node, names) {
13887           var list = classList(node),
13888               i = -1,
13889               n = names.length;
13890
13891           while (++i < n) {
13892             list.add(names[i]);
13893           }
13894         }
13895
13896         function classedRemove(node, names) {
13897           var list = classList(node),
13898               i = -1,
13899               n = names.length;
13900
13901           while (++i < n) {
13902             list.remove(names[i]);
13903           }
13904         }
13905
13906         function classedTrue(names) {
13907           return function () {
13908             classedAdd(this, names);
13909           };
13910         }
13911
13912         function classedFalse(names) {
13913           return function () {
13914             classedRemove(this, names);
13915           };
13916         }
13917
13918         function classedFunction(names, value) {
13919           return function () {
13920             (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
13921           };
13922         }
13923
13924         function selection_classed (name, value) {
13925           var names = classArray(name + "");
13926
13927           if (arguments.length < 2) {
13928             var list = classList(this.node()),
13929                 i = -1,
13930                 n = names.length;
13931
13932             while (++i < n) {
13933               if (!list.contains(names[i])) return false;
13934             }
13935
13936             return true;
13937           }
13938
13939           return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
13940         }
13941
13942         function textRemove() {
13943           this.textContent = "";
13944         }
13945
13946         function textConstant$1(value) {
13947           return function () {
13948             this.textContent = value;
13949           };
13950         }
13951
13952         function textFunction$1(value) {
13953           return function () {
13954             var v = value.apply(this, arguments);
13955             this.textContent = v == null ? "" : v;
13956           };
13957         }
13958
13959         function selection_text (value) {
13960           return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction$1 : textConstant$1)(value)) : this.node().textContent;
13961         }
13962
13963         function htmlRemove() {
13964           this.innerHTML = "";
13965         }
13966
13967         function htmlConstant(value) {
13968           return function () {
13969             this.innerHTML = value;
13970           };
13971         }
13972
13973         function htmlFunction(value) {
13974           return function () {
13975             var v = value.apply(this, arguments);
13976             this.innerHTML = v == null ? "" : v;
13977           };
13978         }
13979
13980         function selection_html (value) {
13981           return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
13982         }
13983
13984         function raise() {
13985           if (this.nextSibling) this.parentNode.appendChild(this);
13986         }
13987
13988         function selection_raise () {
13989           return this.each(raise);
13990         }
13991
13992         function lower() {
13993           if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
13994         }
13995
13996         function selection_lower () {
13997           return this.each(lower);
13998         }
13999
14000         function selection_append (name) {
14001           var create = typeof name === "function" ? name : creator(name);
14002           return this.select(function () {
14003             return this.appendChild(create.apply(this, arguments));
14004           });
14005         }
14006
14007         function constantNull() {
14008           return null;
14009         }
14010
14011         function selection_insert (name, before) {
14012           var create = typeof name === "function" ? name : creator(name),
14013               select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
14014           return this.select(function () {
14015             return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
14016           });
14017         }
14018
14019         function remove$7() {
14020           var parent = this.parentNode;
14021           if (parent) parent.removeChild(this);
14022         }
14023
14024         function selection_remove () {
14025           return this.each(remove$7);
14026         }
14027
14028         function selection_cloneShallow() {
14029           var clone = this.cloneNode(false),
14030               parent = this.parentNode;
14031           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
14032         }
14033
14034         function selection_cloneDeep() {
14035           var clone = this.cloneNode(true),
14036               parent = this.parentNode;
14037           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
14038         }
14039
14040         function selection_clone (deep) {
14041           return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
14042         }
14043
14044         function selection_datum (value) {
14045           return arguments.length ? this.property("__data__", value) : this.node().__data__;
14046         }
14047
14048         function contextListener(listener) {
14049           return function (event) {
14050             listener.call(this, event, this.__data__);
14051           };
14052         }
14053
14054         function parseTypenames(typenames) {
14055           return typenames.trim().split(/^|\s+/).map(function (t) {
14056             var name = "",
14057                 i = t.indexOf(".");
14058             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
14059             return {
14060               type: t,
14061               name: name
14062             };
14063           });
14064         }
14065
14066         function onRemove(typename) {
14067           return function () {
14068             var on = this.__on;
14069             if (!on) return;
14070
14071             for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
14072               if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
14073                 this.removeEventListener(o.type, o.listener, o.options);
14074               } else {
14075                 on[++i] = o;
14076               }
14077             }
14078
14079             if (++i) on.length = i;else delete this.__on;
14080           };
14081         }
14082
14083         function onAdd(typename, value, options) {
14084           return function () {
14085             var on = this.__on,
14086                 o,
14087                 listener = contextListener(value);
14088             if (on) for (var j = 0, m = on.length; j < m; ++j) {
14089               if ((o = on[j]).type === typename.type && o.name === typename.name) {
14090                 this.removeEventListener(o.type, o.listener, o.options);
14091                 this.addEventListener(o.type, o.listener = listener, o.options = options);
14092                 o.value = value;
14093                 return;
14094               }
14095             }
14096             this.addEventListener(typename.type, listener, options);
14097             o = {
14098               type: typename.type,
14099               name: typename.name,
14100               value: value,
14101               listener: listener,
14102               options: options
14103             };
14104             if (!on) this.__on = [o];else on.push(o);
14105           };
14106         }
14107
14108         function selection_on (typename, value, options) {
14109           var typenames = parseTypenames(typename + ""),
14110               i,
14111               n = typenames.length,
14112               t;
14113
14114           if (arguments.length < 2) {
14115             var on = this.node().__on;
14116
14117             if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
14118               for (i = 0, o = on[j]; i < n; ++i) {
14119                 if ((t = typenames[i]).type === o.type && t.name === o.name) {
14120                   return o.value;
14121                 }
14122               }
14123             }
14124             return;
14125           }
14126
14127           on = value ? onAdd : onRemove;
14128
14129           for (i = 0; i < n; ++i) {
14130             this.each(on(typenames[i], value, options));
14131           }
14132
14133           return this;
14134         }
14135
14136         function dispatchEvent(node, type, params) {
14137           var window = defaultView(node),
14138               event = window.CustomEvent;
14139
14140           if (typeof event === "function") {
14141             event = new event(type, params);
14142           } else {
14143             event = window.document.createEvent("Event");
14144             if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;else event.initEvent(type, false, false);
14145           }
14146
14147           node.dispatchEvent(event);
14148         }
14149
14150         function dispatchConstant(type, params) {
14151           return function () {
14152             return dispatchEvent(this, type, params);
14153           };
14154         }
14155
14156         function dispatchFunction(type, params) {
14157           return function () {
14158             return dispatchEvent(this, type, params.apply(this, arguments));
14159           };
14160         }
14161
14162         function selection_dispatch (type, params) {
14163           return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type, params));
14164         }
14165
14166         var _marked = /*#__PURE__*/regeneratorRuntime.mark(_callee);
14167
14168         function _callee() {
14169           var groups, j, m, group, i, n, node;
14170           return regeneratorRuntime.wrap(function _callee$(_context) {
14171             while (1) {
14172               switch (_context.prev = _context.next) {
14173                 case 0:
14174                   groups = this._groups, j = 0, m = groups.length;
14175
14176                 case 1:
14177                   if (!(j < m)) {
14178                     _context.next = 13;
14179                     break;
14180                   }
14181
14182                   group = groups[j], i = 0, n = group.length;
14183
14184                 case 3:
14185                   if (!(i < n)) {
14186                     _context.next = 10;
14187                     break;
14188                   }
14189
14190                   if (!(node = group[i])) {
14191                     _context.next = 7;
14192                     break;
14193                   }
14194
14195                   _context.next = 7;
14196                   return node;
14197
14198                 case 7:
14199                   ++i;
14200                   _context.next = 3;
14201                   break;
14202
14203                 case 10:
14204                   ++j;
14205                   _context.next = 1;
14206                   break;
14207
14208                 case 13:
14209                 case "end":
14210                   return _context.stop();
14211               }
14212             }
14213           }, _marked, this);
14214         }
14215
14216         var root$1 = [null];
14217         function Selection$1(groups, parents) {
14218           this._groups = groups;
14219           this._parents = parents;
14220         }
14221
14222         function selection() {
14223           return new Selection$1([[document.documentElement]], root$1);
14224         }
14225
14226         function selection_selection() {
14227           return this;
14228         }
14229
14230         Selection$1.prototype = selection.prototype = _defineProperty({
14231           constructor: Selection$1,
14232           select: selection_select,
14233           selectAll: selection_selectAll,
14234           selectChild: selection_selectChild,
14235           selectChildren: selection_selectChildren,
14236           filter: selection_filter,
14237           data: selection_data,
14238           enter: selection_enter,
14239           exit: selection_exit,
14240           join: selection_join,
14241           merge: selection_merge,
14242           selection: selection_selection,
14243           order: selection_order,
14244           sort: selection_sort,
14245           call: selection_call,
14246           nodes: selection_nodes,
14247           node: selection_node,
14248           size: selection_size,
14249           empty: selection_empty,
14250           each: selection_each,
14251           attr: selection_attr,
14252           style: selection_style,
14253           property: selection_property,
14254           classed: selection_classed,
14255           text: selection_text,
14256           html: selection_html,
14257           raise: selection_raise,
14258           lower: selection_lower,
14259           append: selection_append,
14260           insert: selection_insert,
14261           remove: selection_remove,
14262           clone: selection_clone,
14263           datum: selection_datum,
14264           on: selection_on,
14265           dispatch: selection_dispatch
14266         }, Symbol.iterator, _callee);
14267
14268         function select (selector) {
14269           return typeof selector === "string" ? new Selection$1([[document.querySelector(selector)]], [document.documentElement]) : new Selection$1([[selector]], root$1);
14270         }
14271
14272         function sourceEvent (event) {
14273           var sourceEvent;
14274
14275           while (sourceEvent = event.sourceEvent) {
14276             event = sourceEvent;
14277           }
14278
14279           return event;
14280         }
14281
14282         function pointer (event, node) {
14283           event = sourceEvent(event);
14284           if (node === undefined) node = event.currentTarget;
14285
14286           if (node) {
14287             var svg = node.ownerSVGElement || node;
14288
14289             if (svg.createSVGPoint) {
14290               var point = svg.createSVGPoint();
14291               point.x = event.clientX, point.y = event.clientY;
14292               point = point.matrixTransform(node.getScreenCTM().inverse());
14293               return [point.x, point.y];
14294             }
14295
14296             if (node.getBoundingClientRect) {
14297               var rect = node.getBoundingClientRect();
14298               return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
14299             }
14300           }
14301
14302           return [event.pageX, event.pageY];
14303         }
14304
14305         function selectAll (selector) {
14306           return typeof selector === "string" ? new Selection$1([document.querySelectorAll(selector)], [document.documentElement]) : new Selection$1([selector == null ? [] : array(selector)], root$1);
14307         }
14308
14309         function nopropagation$1(event) {
14310           event.stopImmediatePropagation();
14311         }
14312         function noevent$1 (event) {
14313           event.preventDefault();
14314           event.stopImmediatePropagation();
14315         }
14316
14317         function dragDisable (view) {
14318           var root = view.document.documentElement,
14319               selection = select(view).on("dragstart.drag", noevent$1, true);
14320
14321           if ("onselectstart" in root) {
14322             selection.on("selectstart.drag", noevent$1, true);
14323           } else {
14324             root.__noselect = root.style.MozUserSelect;
14325             root.style.MozUserSelect = "none";
14326           }
14327         }
14328         function yesdrag(view, noclick) {
14329           var root = view.document.documentElement,
14330               selection = select(view).on("dragstart.drag", null);
14331
14332           if (noclick) {
14333             selection.on("click.drag", noevent$1, true);
14334             setTimeout(function () {
14335               selection.on("click.drag", null);
14336             }, 0);
14337           }
14338
14339           if ("onselectstart" in root) {
14340             selection.on("selectstart.drag", null);
14341           } else {
14342             root.style.MozUserSelect = root.__noselect;
14343             delete root.__noselect;
14344           }
14345         }
14346
14347         var constant$2 = (function (x) {
14348           return function () {
14349             return x;
14350           };
14351         });
14352
14353         function DragEvent(type, _ref) {
14354           var sourceEvent = _ref.sourceEvent,
14355               subject = _ref.subject,
14356               target = _ref.target,
14357               identifier = _ref.identifier,
14358               active = _ref.active,
14359               x = _ref.x,
14360               y = _ref.y,
14361               dx = _ref.dx,
14362               dy = _ref.dy,
14363               dispatch = _ref.dispatch;
14364           Object.defineProperties(this, {
14365             type: {
14366               value: type,
14367               enumerable: true,
14368               configurable: true
14369             },
14370             sourceEvent: {
14371               value: sourceEvent,
14372               enumerable: true,
14373               configurable: true
14374             },
14375             subject: {
14376               value: subject,
14377               enumerable: true,
14378               configurable: true
14379             },
14380             target: {
14381               value: target,
14382               enumerable: true,
14383               configurable: true
14384             },
14385             identifier: {
14386               value: identifier,
14387               enumerable: true,
14388               configurable: true
14389             },
14390             active: {
14391               value: active,
14392               enumerable: true,
14393               configurable: true
14394             },
14395             x: {
14396               value: x,
14397               enumerable: true,
14398               configurable: true
14399             },
14400             y: {
14401               value: y,
14402               enumerable: true,
14403               configurable: true
14404             },
14405             dx: {
14406               value: dx,
14407               enumerable: true,
14408               configurable: true
14409             },
14410             dy: {
14411               value: dy,
14412               enumerable: true,
14413               configurable: true
14414             },
14415             _: {
14416               value: dispatch
14417             }
14418           });
14419         }
14420
14421         DragEvent.prototype.on = function () {
14422           var value = this._.on.apply(this._, arguments);
14423
14424           return value === this._ ? this : value;
14425         };
14426
14427         function defaultFilter$2(event) {
14428           return !event.ctrlKey && !event.button;
14429         }
14430
14431         function defaultContainer() {
14432           return this.parentNode;
14433         }
14434
14435         function defaultSubject(event, d) {
14436           return d == null ? {
14437             x: event.x,
14438             y: event.y
14439           } : d;
14440         }
14441
14442         function defaultTouchable$1() {
14443           return navigator.maxTouchPoints || "ontouchstart" in this;
14444         }
14445
14446         function d3_drag () {
14447           var filter = defaultFilter$2,
14448               container = defaultContainer,
14449               subject = defaultSubject,
14450               touchable = defaultTouchable$1,
14451               gestures = {},
14452               listeners = dispatch$8("start", "drag", "end"),
14453               active = 0,
14454               mousedownx,
14455               mousedowny,
14456               mousemoving,
14457               touchending,
14458               clickDistance2 = 0;
14459
14460           function drag(selection) {
14461             selection.on("mousedown.drag", mousedowned).filter(touchable).on("touchstart.drag", touchstarted).on("touchmove.drag", touchmoved).on("touchend.drag touchcancel.drag", touchended).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
14462           }
14463
14464           function mousedowned(event, d) {
14465             if (touchending || !filter.call(this, event, d)) return;
14466             var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
14467             if (!gesture) return;
14468             select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
14469             dragDisable(event.view);
14470             nopropagation$1(event);
14471             mousemoving = false;
14472             mousedownx = event.clientX;
14473             mousedowny = event.clientY;
14474             gesture("start", event);
14475           }
14476
14477           function mousemoved(event) {
14478             noevent$1(event);
14479
14480             if (!mousemoving) {
14481               var dx = event.clientX - mousedownx,
14482                   dy = event.clientY - mousedowny;
14483               mousemoving = dx * dx + dy * dy > clickDistance2;
14484             }
14485
14486             gestures.mouse("drag", event);
14487           }
14488
14489           function mouseupped(event) {
14490             select(event.view).on("mousemove.drag mouseup.drag", null);
14491             yesdrag(event.view, mousemoving);
14492             noevent$1(event);
14493             gestures.mouse("end", event);
14494           }
14495
14496           function touchstarted(event, d) {
14497             if (!filter.call(this, event, d)) return;
14498             var touches = event.changedTouches,
14499                 c = container.call(this, event, d),
14500                 n = touches.length,
14501                 i,
14502                 gesture;
14503
14504             for (i = 0; i < n; ++i) {
14505               if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
14506                 nopropagation$1(event);
14507                 gesture("start", event, touches[i]);
14508               }
14509             }
14510           }
14511
14512           function touchmoved(event) {
14513             var touches = event.changedTouches,
14514                 n = touches.length,
14515                 i,
14516                 gesture;
14517
14518             for (i = 0; i < n; ++i) {
14519               if (gesture = gestures[touches[i].identifier]) {
14520                 noevent$1(event);
14521                 gesture("drag", event, touches[i]);
14522               }
14523             }
14524           }
14525
14526           function touchended(event) {
14527             var touches = event.changedTouches,
14528                 n = touches.length,
14529                 i,
14530                 gesture;
14531             if (touchending) clearTimeout(touchending);
14532             touchending = setTimeout(function () {
14533               touchending = null;
14534             }, 500); // Ghost clicks are delayed!
14535
14536             for (i = 0; i < n; ++i) {
14537               if (gesture = gestures[touches[i].identifier]) {
14538                 nopropagation$1(event);
14539                 gesture("end", event, touches[i]);
14540               }
14541             }
14542           }
14543
14544           function beforestart(that, container, event, d, identifier, touch) {
14545             var dispatch = listeners.copy(),
14546                 p = pointer(touch || event, container),
14547                 dx,
14548                 dy,
14549                 s;
14550             if ((s = subject.call(that, new DragEvent("beforestart", {
14551               sourceEvent: event,
14552               target: drag,
14553               identifier: identifier,
14554               active: active,
14555               x: p[0],
14556               y: p[1],
14557               dx: 0,
14558               dy: 0,
14559               dispatch: dispatch
14560             }), d)) == null) return;
14561             dx = s.x - p[0] || 0;
14562             dy = s.y - p[1] || 0;
14563             return function gesture(type, event, touch) {
14564               var p0 = p,
14565                   n;
14566
14567               switch (type) {
14568                 case "start":
14569                   gestures[identifier] = gesture, n = active++;
14570                   break;
14571
14572                 case "end":
14573                   delete gestures[identifier], --active;
14574                 // nobreak
14575
14576                 case "drag":
14577                   p = pointer(touch || event, container), n = active;
14578                   break;
14579               }
14580
14581               dispatch.call(type, that, new DragEvent(type, {
14582                 sourceEvent: event,
14583                 subject: s,
14584                 target: drag,
14585                 identifier: identifier,
14586                 active: n,
14587                 x: p[0] + dx,
14588                 y: p[1] + dy,
14589                 dx: p[0] - p0[0],
14590                 dy: p[1] - p0[1],
14591                 dispatch: dispatch
14592               }), d);
14593             };
14594           }
14595
14596           drag.filter = function (_) {
14597             return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter;
14598           };
14599
14600           drag.container = function (_) {
14601             return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container;
14602           };
14603
14604           drag.subject = function (_) {
14605             return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject;
14606           };
14607
14608           drag.touchable = function (_) {
14609             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$2(!!_), drag) : touchable;
14610           };
14611
14612           drag.on = function () {
14613             var value = listeners.on.apply(listeners, arguments);
14614             return value === listeners ? drag : value;
14615           };
14616
14617           drag.clickDistance = function (_) {
14618             return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
14619           };
14620
14621           return drag;
14622         }
14623
14624         var defineProperty$1 = objectDefineProperty.f;
14625         var getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
14626
14627
14628
14629
14630
14631
14632         var enforceInternalState = internalState.enforce;
14633
14634
14635
14636
14637
14638         var MATCH$1 = wellKnownSymbol('match');
14639         var NativeRegExp = global$2.RegExp;
14640         var RegExpPrototype = NativeRegExp.prototype;
14641         // TODO: Use only propper RegExpIdentifierName
14642         var IS_NCG = /^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/;
14643         var re1 = /a/g;
14644         var re2 = /a/g;
14645
14646         // "new" should create a new object, old webkit bug
14647         var CORRECT_NEW = new NativeRegExp(re1) !== re1;
14648
14649         var UNSUPPORTED_Y = regexpStickyHelpers.UNSUPPORTED_Y;
14650
14651         var BASE_FORCED = descriptors &&
14652           (!CORRECT_NEW || UNSUPPORTED_Y || regexpUnsupportedDotAll || regexpUnsupportedNcg || fails(function () {
14653             re2[MATCH$1] = false;
14654             // RegExp constructor can alter flags and IsRegExp works correct with @@match
14655             return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
14656           }));
14657
14658         var handleDotAll = function (string) {
14659           var length = string.length;
14660           var index = 0;
14661           var result = '';
14662           var brackets = false;
14663           var chr;
14664           for (; index <= length; index++) {
14665             chr = string.charAt(index);
14666             if (chr === '\\') {
14667               result += chr + string.charAt(++index);
14668               continue;
14669             }
14670             if (!brackets && chr === '.') {
14671               result += '[\\s\\S]';
14672             } else {
14673               if (chr === '[') {
14674                 brackets = true;
14675               } else if (chr === ']') {
14676                 brackets = false;
14677               } result += chr;
14678             }
14679           } return result;
14680         };
14681
14682         var handleNCG = function (string) {
14683           var length = string.length;
14684           var index = 0;
14685           var result = '';
14686           var named = [];
14687           var names = {};
14688           var brackets = false;
14689           var ncg = false;
14690           var groupid = 0;
14691           var groupname = '';
14692           var chr;
14693           for (; index <= length; index++) {
14694             chr = string.charAt(index);
14695             if (chr === '\\') {
14696               chr = chr + string.charAt(++index);
14697             } else if (chr === ']') {
14698               brackets = false;
14699             } else if (!brackets) switch (true) {
14700               case chr === '[':
14701                 brackets = true;
14702                 break;
14703               case chr === '(':
14704                 if (IS_NCG.test(string.slice(index + 1))) {
14705                   index += 2;
14706                   ncg = true;
14707                 }
14708                 result += chr;
14709                 groupid++;
14710                 continue;
14711               case chr === '>' && ncg:
14712                 if (groupname === '' || has$1(names, groupname)) {
14713                   throw new SyntaxError('Invalid capture group name');
14714                 }
14715                 names[groupname] = true;
14716                 named.push([groupname, groupid]);
14717                 ncg = false;
14718                 groupname = '';
14719                 continue;
14720             }
14721             if (ncg) groupname += chr;
14722             else result += chr;
14723           } return [result, named];
14724         };
14725
14726         // `RegExp` constructor
14727         // https://tc39.es/ecma262/#sec-regexp-constructor
14728         if (isForced_1('RegExp', BASE_FORCED)) {
14729           var RegExpWrapper = function RegExp(pattern, flags) {
14730             var thisIsRegExp = this instanceof RegExpWrapper;
14731             var patternIsRegExp = isRegexp(pattern);
14732             var flagsAreUndefined = flags === undefined;
14733             var groups = [];
14734             var rawPattern = pattern;
14735             var rawFlags, dotAll, sticky, handled, result, state;
14736
14737             if (!thisIsRegExp && patternIsRegExp && flagsAreUndefined && pattern.constructor === RegExpWrapper) {
14738               return pattern;
14739             }
14740
14741             if (patternIsRegExp || pattern instanceof RegExpWrapper) {
14742               pattern = pattern.source;
14743               if (flagsAreUndefined) flags = 'flags' in rawPattern ? rawPattern.flags : regexpFlags.call(rawPattern);
14744             }
14745
14746             pattern = pattern === undefined ? '' : String(pattern);
14747             flags = flags === undefined ? '' : String(flags);
14748             rawPattern = pattern;
14749
14750             if (regexpUnsupportedDotAll && 'dotAll' in re1) {
14751               dotAll = !!flags && flags.indexOf('s') > -1;
14752               if (dotAll) flags = flags.replace(/s/g, '');
14753             }
14754
14755             rawFlags = flags;
14756
14757             if (UNSUPPORTED_Y && 'sticky' in re1) {
14758               sticky = !!flags && flags.indexOf('y') > -1;
14759               if (sticky) flags = flags.replace(/y/g, '');
14760             }
14761
14762             if (regexpUnsupportedNcg) {
14763               handled = handleNCG(pattern);
14764               pattern = handled[0];
14765               groups = handled[1];
14766             }
14767
14768             result = inheritIfRequired(NativeRegExp(pattern, flags), thisIsRegExp ? this : RegExpPrototype, RegExpWrapper);
14769
14770             if (dotAll || sticky || groups.length) {
14771               state = enforceInternalState(result);
14772               if (dotAll) {
14773                 state.dotAll = true;
14774                 state.raw = RegExpWrapper(handleDotAll(pattern), rawFlags);
14775               }
14776               if (sticky) state.sticky = true;
14777               if (groups.length) state.groups = groups;
14778             }
14779
14780             if (pattern !== rawPattern) try {
14781               // fails in old engines, but we have no alternatives for unsupported regex syntax
14782               createNonEnumerableProperty(result, 'source', rawPattern === '' ? '(?:)' : rawPattern);
14783             } catch (error) { /* empty */ }
14784
14785             return result;
14786           };
14787
14788           var proxy = function (key) {
14789             key in RegExpWrapper || defineProperty$1(RegExpWrapper, key, {
14790               configurable: true,
14791               get: function () { return NativeRegExp[key]; },
14792               set: function (it) { NativeRegExp[key] = it; }
14793             });
14794           };
14795
14796           for (var keys$1 = getOwnPropertyNames$1(NativeRegExp), index$1 = 0; keys$1.length > index$1;) {
14797             proxy(keys$1[index$1++]);
14798           }
14799
14800           RegExpPrototype.constructor = RegExpWrapper;
14801           RegExpWrapper.prototype = RegExpPrototype;
14802           redefine(global$2, 'RegExp', RegExpWrapper);
14803         }
14804
14805         // https://tc39.es/ecma262/#sec-get-regexp-@@species
14806         setSpecies('RegExp');
14807
14808         function define (constructor, factory, prototype) {
14809           constructor.prototype = factory.prototype = prototype;
14810           prototype.constructor = constructor;
14811         }
14812         function extend$3(parent, definition) {
14813           var prototype = Object.create(parent.prototype);
14814
14815           for (var key in definition) {
14816             prototype[key] = definition[key];
14817           }
14818
14819           return prototype;
14820         }
14821
14822         function Color() {}
14823         var _darker = 0.7;
14824
14825         var _brighter = 1 / _darker;
14826         var reI = "\\s*([+-]?\\d+)\\s*",
14827             reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
14828             reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
14829             reHex = /^#([0-9a-f]{3,8})$/,
14830             reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
14831             reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
14832             reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
14833             reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
14834             reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
14835             reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
14836         var named = {
14837           aliceblue: 0xf0f8ff,
14838           antiquewhite: 0xfaebd7,
14839           aqua: 0x00ffff,
14840           aquamarine: 0x7fffd4,
14841           azure: 0xf0ffff,
14842           beige: 0xf5f5dc,
14843           bisque: 0xffe4c4,
14844           black: 0x000000,
14845           blanchedalmond: 0xffebcd,
14846           blue: 0x0000ff,
14847           blueviolet: 0x8a2be2,
14848           brown: 0xa52a2a,
14849           burlywood: 0xdeb887,
14850           cadetblue: 0x5f9ea0,
14851           chartreuse: 0x7fff00,
14852           chocolate: 0xd2691e,
14853           coral: 0xff7f50,
14854           cornflowerblue: 0x6495ed,
14855           cornsilk: 0xfff8dc,
14856           crimson: 0xdc143c,
14857           cyan: 0x00ffff,
14858           darkblue: 0x00008b,
14859           darkcyan: 0x008b8b,
14860           darkgoldenrod: 0xb8860b,
14861           darkgray: 0xa9a9a9,
14862           darkgreen: 0x006400,
14863           darkgrey: 0xa9a9a9,
14864           darkkhaki: 0xbdb76b,
14865           darkmagenta: 0x8b008b,
14866           darkolivegreen: 0x556b2f,
14867           darkorange: 0xff8c00,
14868           darkorchid: 0x9932cc,
14869           darkred: 0x8b0000,
14870           darksalmon: 0xe9967a,
14871           darkseagreen: 0x8fbc8f,
14872           darkslateblue: 0x483d8b,
14873           darkslategray: 0x2f4f4f,
14874           darkslategrey: 0x2f4f4f,
14875           darkturquoise: 0x00ced1,
14876           darkviolet: 0x9400d3,
14877           deeppink: 0xff1493,
14878           deepskyblue: 0x00bfff,
14879           dimgray: 0x696969,
14880           dimgrey: 0x696969,
14881           dodgerblue: 0x1e90ff,
14882           firebrick: 0xb22222,
14883           floralwhite: 0xfffaf0,
14884           forestgreen: 0x228b22,
14885           fuchsia: 0xff00ff,
14886           gainsboro: 0xdcdcdc,
14887           ghostwhite: 0xf8f8ff,
14888           gold: 0xffd700,
14889           goldenrod: 0xdaa520,
14890           gray: 0x808080,
14891           green: 0x008000,
14892           greenyellow: 0xadff2f,
14893           grey: 0x808080,
14894           honeydew: 0xf0fff0,
14895           hotpink: 0xff69b4,
14896           indianred: 0xcd5c5c,
14897           indigo: 0x4b0082,
14898           ivory: 0xfffff0,
14899           khaki: 0xf0e68c,
14900           lavender: 0xe6e6fa,
14901           lavenderblush: 0xfff0f5,
14902           lawngreen: 0x7cfc00,
14903           lemonchiffon: 0xfffacd,
14904           lightblue: 0xadd8e6,
14905           lightcoral: 0xf08080,
14906           lightcyan: 0xe0ffff,
14907           lightgoldenrodyellow: 0xfafad2,
14908           lightgray: 0xd3d3d3,
14909           lightgreen: 0x90ee90,
14910           lightgrey: 0xd3d3d3,
14911           lightpink: 0xffb6c1,
14912           lightsalmon: 0xffa07a,
14913           lightseagreen: 0x20b2aa,
14914           lightskyblue: 0x87cefa,
14915           lightslategray: 0x778899,
14916           lightslategrey: 0x778899,
14917           lightsteelblue: 0xb0c4de,
14918           lightyellow: 0xffffe0,
14919           lime: 0x00ff00,
14920           limegreen: 0x32cd32,
14921           linen: 0xfaf0e6,
14922           magenta: 0xff00ff,
14923           maroon: 0x800000,
14924           mediumaquamarine: 0x66cdaa,
14925           mediumblue: 0x0000cd,
14926           mediumorchid: 0xba55d3,
14927           mediumpurple: 0x9370db,
14928           mediumseagreen: 0x3cb371,
14929           mediumslateblue: 0x7b68ee,
14930           mediumspringgreen: 0x00fa9a,
14931           mediumturquoise: 0x48d1cc,
14932           mediumvioletred: 0xc71585,
14933           midnightblue: 0x191970,
14934           mintcream: 0xf5fffa,
14935           mistyrose: 0xffe4e1,
14936           moccasin: 0xffe4b5,
14937           navajowhite: 0xffdead,
14938           navy: 0x000080,
14939           oldlace: 0xfdf5e6,
14940           olive: 0x808000,
14941           olivedrab: 0x6b8e23,
14942           orange: 0xffa500,
14943           orangered: 0xff4500,
14944           orchid: 0xda70d6,
14945           palegoldenrod: 0xeee8aa,
14946           palegreen: 0x98fb98,
14947           paleturquoise: 0xafeeee,
14948           palevioletred: 0xdb7093,
14949           papayawhip: 0xffefd5,
14950           peachpuff: 0xffdab9,
14951           peru: 0xcd853f,
14952           pink: 0xffc0cb,
14953           plum: 0xdda0dd,
14954           powderblue: 0xb0e0e6,
14955           purple: 0x800080,
14956           rebeccapurple: 0x663399,
14957           red: 0xff0000,
14958           rosybrown: 0xbc8f8f,
14959           royalblue: 0x4169e1,
14960           saddlebrown: 0x8b4513,
14961           salmon: 0xfa8072,
14962           sandybrown: 0xf4a460,
14963           seagreen: 0x2e8b57,
14964           seashell: 0xfff5ee,
14965           sienna: 0xa0522d,
14966           silver: 0xc0c0c0,
14967           skyblue: 0x87ceeb,
14968           slateblue: 0x6a5acd,
14969           slategray: 0x708090,
14970           slategrey: 0x708090,
14971           snow: 0xfffafa,
14972           springgreen: 0x00ff7f,
14973           steelblue: 0x4682b4,
14974           tan: 0xd2b48c,
14975           teal: 0x008080,
14976           thistle: 0xd8bfd8,
14977           tomato: 0xff6347,
14978           turquoise: 0x40e0d0,
14979           violet: 0xee82ee,
14980           wheat: 0xf5deb3,
14981           white: 0xffffff,
14982           whitesmoke: 0xf5f5f5,
14983           yellow: 0xffff00,
14984           yellowgreen: 0x9acd32
14985         };
14986         define(Color, color, {
14987           copy: function copy(channels) {
14988             return Object.assign(new this.constructor(), this, channels);
14989           },
14990           displayable: function displayable() {
14991             return this.rgb().displayable();
14992           },
14993           hex: color_formatHex,
14994           // Deprecated! Use color.formatHex.
14995           formatHex: color_formatHex,
14996           formatHsl: color_formatHsl,
14997           formatRgb: color_formatRgb,
14998           toString: color_formatRgb
14999         });
15000
15001         function color_formatHex() {
15002           return this.rgb().formatHex();
15003         }
15004
15005         function color_formatHsl() {
15006           return hslConvert(this).formatHsl();
15007         }
15008
15009         function color_formatRgb() {
15010           return this.rgb().formatRgb();
15011         }
15012
15013         function color(format) {
15014           var m, l;
15015           format = (format + "").trim().toLowerCase();
15016           return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000
15017           : l === 3 ? new Rgb(m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, (m & 0xf) << 4 | m & 0xf, 1) // #f00
15018           : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000
15019           : l === 4 ? rgba(m >> 12 & 0xf | m >> 8 & 0xf0, m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, ((m & 0xf) << 4 | m & 0xf) / 0xff) // #f000
15020           : null // invalid hex
15021           ) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
15022           : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
15023           : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
15024           : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
15025           : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
15026           : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
15027           : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
15028           : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
15029         }
15030
15031         function rgbn(n) {
15032           return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
15033         }
15034
15035         function rgba(r, g, b, a) {
15036           if (a <= 0) r = g = b = NaN;
15037           return new Rgb(r, g, b, a);
15038         }
15039
15040         function rgbConvert(o) {
15041           if (!(o instanceof Color)) o = color(o);
15042           if (!o) return new Rgb();
15043           o = o.rgb();
15044           return new Rgb(o.r, o.g, o.b, o.opacity);
15045         }
15046         function rgb(r, g, b, opacity) {
15047           return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
15048         }
15049         function Rgb(r, g, b, opacity) {
15050           this.r = +r;
15051           this.g = +g;
15052           this.b = +b;
15053           this.opacity = +opacity;
15054         }
15055         define(Rgb, rgb, extend$3(Color, {
15056           brighter: function brighter(k) {
15057             k = k == null ? _brighter : Math.pow(_brighter, k);
15058             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
15059           },
15060           darker: function darker(k) {
15061             k = k == null ? _darker : Math.pow(_darker, k);
15062             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
15063           },
15064           rgb: function rgb() {
15065             return this;
15066           },
15067           displayable: function displayable() {
15068             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;
15069           },
15070           hex: rgb_formatHex,
15071           // Deprecated! Use color.formatHex.
15072           formatHex: rgb_formatHex,
15073           formatRgb: rgb_formatRgb,
15074           toString: rgb_formatRgb
15075         }));
15076
15077         function rgb_formatHex() {
15078           return "#" + hex$1(this.r) + hex$1(this.g) + hex$1(this.b);
15079         }
15080
15081         function rgb_formatRgb() {
15082           var a = this.opacity;
15083           a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
15084           return (a === 1 ? "rgb(" : "rgba(") + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", " + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", " + Math.max(0, Math.min(255, Math.round(this.b) || 0)) + (a === 1 ? ")" : ", " + a + ")");
15085         }
15086
15087         function hex$1(value) {
15088           value = Math.max(0, Math.min(255, Math.round(value) || 0));
15089           return (value < 16 ? "0" : "") + value.toString(16);
15090         }
15091
15092         function hsla(h, s, l, a) {
15093           if (a <= 0) h = s = l = NaN;else if (l <= 0 || l >= 1) h = s = NaN;else if (s <= 0) h = NaN;
15094           return new Hsl(h, s, l, a);
15095         }
15096
15097         function hslConvert(o) {
15098           if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
15099           if (!(o instanceof Color)) o = color(o);
15100           if (!o) return new Hsl();
15101           if (o instanceof Hsl) return o;
15102           o = o.rgb();
15103           var r = o.r / 255,
15104               g = o.g / 255,
15105               b = o.b / 255,
15106               min = Math.min(r, g, b),
15107               max = Math.max(r, g, b),
15108               h = NaN,
15109               s = max - min,
15110               l = (max + min) / 2;
15111
15112           if (s) {
15113             if (r === max) h = (g - b) / s + (g < b) * 6;else if (g === max) h = (b - r) / s + 2;else h = (r - g) / s + 4;
15114             s /= l < 0.5 ? max + min : 2 - max - min;
15115             h *= 60;
15116           } else {
15117             s = l > 0 && l < 1 ? 0 : h;
15118           }
15119
15120           return new Hsl(h, s, l, o.opacity);
15121         }
15122         function hsl(h, s, l, opacity) {
15123           return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
15124         }
15125
15126         function Hsl(h, s, l, opacity) {
15127           this.h = +h;
15128           this.s = +s;
15129           this.l = +l;
15130           this.opacity = +opacity;
15131         }
15132
15133         define(Hsl, hsl, extend$3(Color, {
15134           brighter: function brighter(k) {
15135             k = k == null ? _brighter : Math.pow(_brighter, k);
15136             return new Hsl(this.h, this.s, this.l * k, this.opacity);
15137           },
15138           darker: function darker(k) {
15139             k = k == null ? _darker : Math.pow(_darker, k);
15140             return new Hsl(this.h, this.s, this.l * k, this.opacity);
15141           },
15142           rgb: function rgb() {
15143             var h = this.h % 360 + (this.h < 0) * 360,
15144                 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
15145                 l = this.l,
15146                 m2 = l + (l < 0.5 ? l : 1 - l) * s,
15147                 m1 = 2 * l - m2;
15148             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), this.opacity);
15149           },
15150           displayable: function displayable() {
15151             return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
15152           },
15153           formatHsl: function formatHsl() {
15154             var a = this.opacity;
15155             a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
15156             return (a === 1 ? "hsl(" : "hsla(") + (this.h || 0) + ", " + (this.s || 0) * 100 + "%, " + (this.l || 0) * 100 + "%" + (a === 1 ? ")" : ", " + a + ")");
15157           }
15158         }));
15159         /* From FvD 13.37, CSS Color Module Level 3 */
15160
15161         function hsl2rgb(h, m1, m2) {
15162           return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
15163         }
15164
15165         var constant$1 = (function (x) {
15166           return function () {
15167             return x;
15168           };
15169         });
15170
15171         function linear$2(a, d) {
15172           return function (t) {
15173             return a + t * d;
15174           };
15175         }
15176
15177         function exponential(a, b, y) {
15178           return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function (t) {
15179             return Math.pow(a + t * b, y);
15180           };
15181         }
15182         function gamma(y) {
15183           return (y = +y) === 1 ? nogamma : function (a, b) {
15184             return b - a ? exponential(a, b, y) : constant$1(isNaN(a) ? b : a);
15185           };
15186         }
15187         function nogamma(a, b) {
15188           var d = b - a;
15189           return d ? linear$2(a, d) : constant$1(isNaN(a) ? b : a);
15190         }
15191
15192         var d3_interpolateRgb = (function rgbGamma(y) {
15193           var color = gamma(y);
15194
15195           function rgb$1(start, end) {
15196             var r = color((start = rgb(start)).r, (end = rgb(end)).r),
15197                 g = color(start.g, end.g),
15198                 b = color(start.b, end.b),
15199                 opacity = nogamma(start.opacity, end.opacity);
15200             return function (t) {
15201               start.r = r(t);
15202               start.g = g(t);
15203               start.b = b(t);
15204               start.opacity = opacity(t);
15205               return start + "";
15206             };
15207           }
15208
15209           rgb$1.gamma = rgbGamma;
15210           return rgb$1;
15211         })(1);
15212
15213         function numberArray (a, b) {
15214           if (!b) b = [];
15215           var n = a ? Math.min(b.length, a.length) : 0,
15216               c = b.slice(),
15217               i;
15218           return function (t) {
15219             for (i = 0; i < n; ++i) {
15220               c[i] = a[i] * (1 - t) + b[i] * t;
15221             }
15222
15223             return c;
15224           };
15225         }
15226         function isNumberArray(x) {
15227           return ArrayBuffer.isView(x) && !(x instanceof DataView);
15228         }
15229
15230         function genericArray(a, b) {
15231           var nb = b ? b.length : 0,
15232               na = a ? Math.min(nb, a.length) : 0,
15233               x = new Array(na),
15234               c = new Array(nb),
15235               i;
15236
15237           for (i = 0; i < na; ++i) {
15238             x[i] = interpolate$1(a[i], b[i]);
15239           }
15240
15241           for (; i < nb; ++i) {
15242             c[i] = b[i];
15243           }
15244
15245           return function (t) {
15246             for (i = 0; i < na; ++i) {
15247               c[i] = x[i](t);
15248             }
15249
15250             return c;
15251           };
15252         }
15253
15254         function date (a, b) {
15255           var d = new Date();
15256           return a = +a, b = +b, function (t) {
15257             return d.setTime(a * (1 - t) + b * t), d;
15258           };
15259         }
15260
15261         function d3_interpolateNumber (a, b) {
15262           return a = +a, b = +b, function (t) {
15263             return a * (1 - t) + b * t;
15264           };
15265         }
15266
15267         function object (a, b) {
15268           var i = {},
15269               c = {},
15270               k;
15271           if (a === null || _typeof(a) !== "object") a = {};
15272           if (b === null || _typeof(b) !== "object") b = {};
15273
15274           for (k in b) {
15275             if (k in a) {
15276               i[k] = interpolate$1(a[k], b[k]);
15277             } else {
15278               c[k] = b[k];
15279             }
15280           }
15281
15282           return function (t) {
15283             for (k in i) {
15284               c[k] = i[k](t);
15285             }
15286
15287             return c;
15288           };
15289         }
15290
15291         var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
15292             reB = new RegExp(reA.source, "g");
15293
15294         function zero(b) {
15295           return function () {
15296             return b;
15297           };
15298         }
15299
15300         function one(b) {
15301           return function (t) {
15302             return b(t) + "";
15303           };
15304         }
15305
15306         function interpolateString (a, b) {
15307           var bi = reA.lastIndex = reB.lastIndex = 0,
15308               // scan index for next number in b
15309           am,
15310               // current match in a
15311           bm,
15312               // current match in b
15313           bs,
15314               // string preceding current number in b, if any
15315           i = -1,
15316               // index in s
15317           s = [],
15318               // string constants and placeholders
15319           q = []; // number interpolators
15320           // Coerce inputs to strings.
15321
15322           a = a + "", b = b + ""; // Interpolate pairs of numbers in a & b.
15323
15324           while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
15325             if ((bs = bm.index) > bi) {
15326               // a string precedes the next number in b
15327               bs = b.slice(bi, bs);
15328               if (s[i]) s[i] += bs; // coalesce with previous string
15329               else s[++i] = bs;
15330             }
15331
15332             if ((am = am[0]) === (bm = bm[0])) {
15333               // numbers in a & b match
15334               if (s[i]) s[i] += bm; // coalesce with previous string
15335               else s[++i] = bm;
15336             } else {
15337               // interpolate non-matching numbers
15338               s[++i] = null;
15339               q.push({
15340                 i: i,
15341                 x: d3_interpolateNumber(am, bm)
15342               });
15343             }
15344
15345             bi = reB.lastIndex;
15346           } // Add remains of b.
15347
15348
15349           if (bi < b.length) {
15350             bs = b.slice(bi);
15351             if (s[i]) s[i] += bs; // coalesce with previous string
15352             else s[++i] = bs;
15353           } // Special optimization for only a single match.
15354           // Otherwise, interpolate each of the numbers and rejoin the string.
15355
15356
15357           return s.length < 2 ? q[0] ? one(q[0].x) : zero(b) : (b = q.length, function (t) {
15358             for (var i = 0, o; i < b; ++i) {
15359               s[(o = q[i]).i] = o.x(t);
15360             }
15361
15362             return s.join("");
15363           });
15364         }
15365
15366         function interpolate$1 (a, b) {
15367           var t = _typeof(b),
15368               c;
15369
15370           return b == null || t === "boolean" ? constant$1(b) : (t === "number" ? d3_interpolateNumber : t === "string" ? (c = color(b)) ? (b = c, d3_interpolateRgb) : interpolateString : b instanceof color ? d3_interpolateRgb : b instanceof Date ? date : isNumberArray(b) ? numberArray : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object : d3_interpolateNumber)(a, b);
15371         }
15372
15373         function interpolateRound (a, b) {
15374           return a = +a, b = +b, function (t) {
15375             return Math.round(a * (1 - t) + b * t);
15376           };
15377         }
15378
15379         var degrees = 180 / Math.PI;
15380         var identity$3 = {
15381           translateX: 0,
15382           translateY: 0,
15383           rotate: 0,
15384           skewX: 0,
15385           scaleX: 1,
15386           scaleY: 1
15387         };
15388         function decompose (a, b, c, d, e, f) {
15389           var scaleX, scaleY, skewX;
15390           if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
15391           if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
15392           if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
15393           if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
15394           return {
15395             translateX: e,
15396             translateY: f,
15397             rotate: Math.atan2(b, a) * degrees,
15398             skewX: Math.atan(skewX) * degrees,
15399             scaleX: scaleX,
15400             scaleY: scaleY
15401           };
15402         }
15403
15404         var svgNode;
15405         /* eslint-disable no-undef */
15406
15407         function parseCss(value) {
15408           var m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
15409           return m.isIdentity ? identity$3 : decompose(m.a, m.b, m.c, m.d, m.e, m.f);
15410         }
15411         function parseSvg(value) {
15412           if (value == null) return identity$3;
15413           if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
15414           svgNode.setAttribute("transform", value);
15415           if (!(value = svgNode.transform.baseVal.consolidate())) return identity$3;
15416           value = value.matrix;
15417           return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
15418         }
15419
15420         function interpolateTransform(parse, pxComma, pxParen, degParen) {
15421           function pop(s) {
15422             return s.length ? s.pop() + " " : "";
15423           }
15424
15425           function translate(xa, ya, xb, yb, s, q) {
15426             if (xa !== xb || ya !== yb) {
15427               var i = s.push("translate(", null, pxComma, null, pxParen);
15428               q.push({
15429                 i: i - 4,
15430                 x: d3_interpolateNumber(xa, xb)
15431               }, {
15432                 i: i - 2,
15433                 x: d3_interpolateNumber(ya, yb)
15434               });
15435             } else if (xb || yb) {
15436               s.push("translate(" + xb + pxComma + yb + pxParen);
15437             }
15438           }
15439
15440           function rotate(a, b, s, q) {
15441             if (a !== b) {
15442               if (a - b > 180) b += 360;else if (b - a > 180) a += 360; // shortest path
15443
15444               q.push({
15445                 i: s.push(pop(s) + "rotate(", null, degParen) - 2,
15446                 x: d3_interpolateNumber(a, b)
15447               });
15448             } else if (b) {
15449               s.push(pop(s) + "rotate(" + b + degParen);
15450             }
15451           }
15452
15453           function skewX(a, b, s, q) {
15454             if (a !== b) {
15455               q.push({
15456                 i: s.push(pop(s) + "skewX(", null, degParen) - 2,
15457                 x: d3_interpolateNumber(a, b)
15458               });
15459             } else if (b) {
15460               s.push(pop(s) + "skewX(" + b + degParen);
15461             }
15462           }
15463
15464           function scale(xa, ya, xb, yb, s, q) {
15465             if (xa !== xb || ya !== yb) {
15466               var i = s.push(pop(s) + "scale(", null, ",", null, ")");
15467               q.push({
15468                 i: i - 4,
15469                 x: d3_interpolateNumber(xa, xb)
15470               }, {
15471                 i: i - 2,
15472                 x: d3_interpolateNumber(ya, yb)
15473               });
15474             } else if (xb !== 1 || yb !== 1) {
15475               s.push(pop(s) + "scale(" + xb + "," + yb + ")");
15476             }
15477           }
15478
15479           return function (a, b) {
15480             var s = [],
15481                 // string constants and placeholders
15482             q = []; // number interpolators
15483
15484             a = parse(a), b = parse(b);
15485             translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
15486             rotate(a.rotate, b.rotate, s, q);
15487             skewX(a.skewX, b.skewX, s, q);
15488             scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
15489             a = b = null; // gc
15490
15491             return function (t) {
15492               var i = -1,
15493                   n = q.length,
15494                   o;
15495
15496               while (++i < n) {
15497                 s[(o = q[i]).i] = o.x(t);
15498               }
15499
15500               return s.join("");
15501             };
15502           };
15503         }
15504
15505         var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
15506         var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
15507
15508         var epsilon2 = 1e-12;
15509
15510         function cosh(x) {
15511           return ((x = Math.exp(x)) + 1 / x) / 2;
15512         }
15513
15514         function sinh(x) {
15515           return ((x = Math.exp(x)) - 1 / x) / 2;
15516         }
15517
15518         function tanh(x) {
15519           return ((x = Math.exp(2 * x)) - 1) / (x + 1);
15520         }
15521
15522         var interpolateZoom = (function zoomRho(rho, rho2, rho4) {
15523           // p0 = [ux0, uy0, w0]
15524           // p1 = [ux1, uy1, w1]
15525           function zoom(p0, p1) {
15526             var ux0 = p0[0],
15527                 uy0 = p0[1],
15528                 w0 = p0[2],
15529                 ux1 = p1[0],
15530                 uy1 = p1[1],
15531                 w1 = p1[2],
15532                 dx = ux1 - ux0,
15533                 dy = uy1 - uy0,
15534                 d2 = dx * dx + dy * dy,
15535                 i,
15536                 S; // Special case for u0 ≅ u1.
15537
15538             if (d2 < epsilon2) {
15539               S = Math.log(w1 / w0) / rho;
15540
15541               i = function i(t) {
15542                 return [ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(rho * t * S)];
15543               };
15544             } // General case.
15545             else {
15546                 var d1 = Math.sqrt(d2),
15547                     b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
15548                     b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
15549                     r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
15550                     r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
15551                 S = (r1 - r0) / rho;
15552
15553                 i = function i(t) {
15554                   var s = t * S,
15555                       coshr0 = cosh(r0),
15556                       u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
15557                   return [ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / cosh(rho * s + r0)];
15558                 };
15559               }
15560
15561             i.duration = S * 1000 * rho / Math.SQRT2;
15562             return i;
15563           }
15564
15565           zoom.rho = function (_) {
15566             var _1 = Math.max(1e-3, +_),
15567                 _2 = _1 * _1,
15568                 _4 = _2 * _2;
15569
15570             return zoomRho(_1, _2, _4);
15571           };
15572
15573           return zoom;
15574         })(Math.SQRT2, 2, 4);
15575
15576         function d3_quantize (interpolator, n) {
15577           var samples = new Array(n);
15578
15579           for (var i = 0; i < n; ++i) {
15580             samples[i] = interpolator(i / (n - 1));
15581           }
15582
15583           return samples;
15584         }
15585
15586         // `Function.prototype.bind` method
15587         // https://tc39.es/ecma262/#sec-function.prototype.bind
15588         _export({ target: 'Function', proto: true }, {
15589           bind: functionBind
15590         });
15591
15592         var frame = 0,
15593             // is an animation frame pending?
15594         timeout = 0,
15595             // is a timeout pending?
15596         interval = 0,
15597             // are any timers active?
15598         pokeDelay = 1000,
15599             // how frequently we check for clock skew
15600         taskHead,
15601             taskTail,
15602             clockLast = 0,
15603             clockNow = 0,
15604             clockSkew = 0,
15605             clock = (typeof performance === "undefined" ? "undefined" : _typeof(performance)) === "object" && performance.now ? performance : Date,
15606             setFrame = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function (f) {
15607           setTimeout(f, 17);
15608         };
15609         function now$1() {
15610           return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
15611         }
15612
15613         function clearNow() {
15614           clockNow = 0;
15615         }
15616
15617         function Timer() {
15618           this._call = this._time = this._next = null;
15619         }
15620         Timer.prototype = timer.prototype = {
15621           constructor: Timer,
15622           restart: function restart(callback, delay, time) {
15623             if (typeof callback !== "function") throw new TypeError("callback is not a function");
15624             time = (time == null ? now$1() : +time) + (delay == null ? 0 : +delay);
15625
15626             if (!this._next && taskTail !== this) {
15627               if (taskTail) taskTail._next = this;else taskHead = this;
15628               taskTail = this;
15629             }
15630
15631             this._call = callback;
15632             this._time = time;
15633             sleep();
15634           },
15635           stop: function stop() {
15636             if (this._call) {
15637               this._call = null;
15638               this._time = Infinity;
15639               sleep();
15640             }
15641           }
15642         };
15643         function timer(callback, delay, time) {
15644           var t = new Timer();
15645           t.restart(callback, delay, time);
15646           return t;
15647         }
15648         function timerFlush() {
15649           now$1(); // Get the current time, if not already set.
15650
15651           ++frame; // Pretend we’ve set an alarm, if we haven’t already.
15652
15653           var t = taskHead,
15654               e;
15655
15656           while (t) {
15657             if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
15658             t = t._next;
15659           }
15660
15661           --frame;
15662         }
15663
15664         function wake() {
15665           clockNow = (clockLast = clock.now()) + clockSkew;
15666           frame = timeout = 0;
15667
15668           try {
15669             timerFlush();
15670           } finally {
15671             frame = 0;
15672             nap();
15673             clockNow = 0;
15674           }
15675         }
15676
15677         function poke() {
15678           var now = clock.now(),
15679               delay = now - clockLast;
15680           if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
15681         }
15682
15683         function nap() {
15684           var t0,
15685               t1 = taskHead,
15686               t2,
15687               time = Infinity;
15688
15689           while (t1) {
15690             if (t1._call) {
15691               if (time > t1._time) time = t1._time;
15692               t0 = t1, t1 = t1._next;
15693             } else {
15694               t2 = t1._next, t1._next = null;
15695               t1 = t0 ? t0._next = t2 : taskHead = t2;
15696             }
15697           }
15698
15699           taskTail = t0;
15700           sleep(time);
15701         }
15702
15703         function sleep(time) {
15704           if (frame) return; // Soonest alarm already set, or will be.
15705
15706           if (timeout) timeout = clearTimeout(timeout);
15707           var delay = time - clockNow; // Strictly less than if we recomputed clockNow.
15708
15709           if (delay > 24) {
15710             if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
15711             if (interval) interval = clearInterval(interval);
15712           } else {
15713             if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
15714             frame = 1, setFrame(wake);
15715           }
15716         }
15717
15718         function d3_timeout (callback, delay, time) {
15719           var t = new Timer();
15720           delay = delay == null ? 0 : +delay;
15721           t.restart(function (elapsed) {
15722             t.stop();
15723             callback(elapsed + delay);
15724           }, delay, time);
15725           return t;
15726         }
15727
15728         var emptyOn = dispatch$8("start", "end", "cancel", "interrupt");
15729         var emptyTween = [];
15730         var CREATED = 0;
15731         var SCHEDULED = 1;
15732         var STARTING = 2;
15733         var STARTED = 3;
15734         var RUNNING = 4;
15735         var ENDING = 5;
15736         var ENDED = 6;
15737         function schedule (node, name, id, index, group, timing) {
15738           var schedules = node.__transition;
15739           if (!schedules) node.__transition = {};else if (id in schedules) return;
15740           create$2(node, id, {
15741             name: name,
15742             index: index,
15743             // For context during callback.
15744             group: group,
15745             // For context during callback.
15746             on: emptyOn,
15747             tween: emptyTween,
15748             time: timing.time,
15749             delay: timing.delay,
15750             duration: timing.duration,
15751             ease: timing.ease,
15752             timer: null,
15753             state: CREATED
15754           });
15755         }
15756         function init(node, id) {
15757           var schedule = get$1(node, id);
15758           if (schedule.state > CREATED) throw new Error("too late; already scheduled");
15759           return schedule;
15760         }
15761         function set(node, id) {
15762           var schedule = get$1(node, id);
15763           if (schedule.state > STARTED) throw new Error("too late; already running");
15764           return schedule;
15765         }
15766         function get$1(node, id) {
15767           var schedule = node.__transition;
15768           if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found");
15769           return schedule;
15770         }
15771
15772         function create$2(node, id, self) {
15773           var schedules = node.__transition,
15774               tween; // Initialize the self timer when the transition is created.
15775           // Note the actual delay is not known until the first callback!
15776
15777           schedules[id] = self;
15778           self.timer = timer(schedule, 0, self.time);
15779
15780           function schedule(elapsed) {
15781             self.state = SCHEDULED;
15782             self.timer.restart(start, self.delay, self.time); // If the elapsed delay is less than our first sleep, start immediately.
15783
15784             if (self.delay <= elapsed) start(elapsed - self.delay);
15785           }
15786
15787           function start(elapsed) {
15788             var i, j, n, o; // If the state is not SCHEDULED, then we previously errored on start.
15789
15790             if (self.state !== SCHEDULED) return stop();
15791
15792             for (i in schedules) {
15793               o = schedules[i];
15794               if (o.name !== self.name) continue; // While this element already has a starting transition during this frame,
15795               // defer starting an interrupting transition until that transition has a
15796               // chance to tick (and possibly end); see d3/d3-transition#54!
15797
15798               if (o.state === STARTED) return d3_timeout(start); // Interrupt the active transition, if any.
15799
15800               if (o.state === RUNNING) {
15801                 o.state = ENDED;
15802                 o.timer.stop();
15803                 o.on.call("interrupt", node, node.__data__, o.index, o.group);
15804                 delete schedules[i];
15805               } // Cancel any pre-empted transitions.
15806               else if (+i < id) {
15807                   o.state = ENDED;
15808                   o.timer.stop();
15809                   o.on.call("cancel", node, node.__data__, o.index, o.group);
15810                   delete schedules[i];
15811                 }
15812             } // Defer the first tick to end of the current frame; see d3/d3#1576.
15813             // Note the transition may be canceled after start and before the first tick!
15814             // Note this must be scheduled before the start event; see d3/d3-transition#16!
15815             // Assuming this is successful, subsequent callbacks go straight to tick.
15816
15817
15818             d3_timeout(function () {
15819               if (self.state === STARTED) {
15820                 self.state = RUNNING;
15821                 self.timer.restart(tick, self.delay, self.time);
15822                 tick(elapsed);
15823               }
15824             }); // Dispatch the start event.
15825             // Note this must be done before the tween are initialized.
15826
15827             self.state = STARTING;
15828             self.on.call("start", node, node.__data__, self.index, self.group);
15829             if (self.state !== STARTING) return; // interrupted
15830
15831             self.state = STARTED; // Initialize the tween, deleting null tween.
15832
15833             tween = new Array(n = self.tween.length);
15834
15835             for (i = 0, j = -1; i < n; ++i) {
15836               if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
15837                 tween[++j] = o;
15838               }
15839             }
15840
15841             tween.length = j + 1;
15842           }
15843
15844           function tick(elapsed) {
15845             var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
15846                 i = -1,
15847                 n = tween.length;
15848
15849             while (++i < n) {
15850               tween[i].call(node, t);
15851             } // Dispatch the end event.
15852
15853
15854             if (self.state === ENDING) {
15855               self.on.call("end", node, node.__data__, self.index, self.group);
15856               stop();
15857             }
15858           }
15859
15860           function stop() {
15861             self.state = ENDED;
15862             self.timer.stop();
15863             delete schedules[id];
15864
15865             for (var i in schedules) {
15866               return;
15867             } // eslint-disable-line no-unused-vars
15868
15869
15870             delete node.__transition;
15871           }
15872         }
15873
15874         function interrupt (node, name) {
15875           var schedules = node.__transition,
15876               schedule,
15877               active,
15878               empty = true,
15879               i;
15880           if (!schedules) return;
15881           name = name == null ? null : name + "";
15882
15883           for (i in schedules) {
15884             if ((schedule = schedules[i]).name !== name) {
15885               empty = false;
15886               continue;
15887             }
15888
15889             active = schedule.state > STARTING && schedule.state < ENDING;
15890             schedule.state = ENDED;
15891             schedule.timer.stop();
15892             schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
15893             delete schedules[i];
15894           }
15895
15896           if (empty) delete node.__transition;
15897         }
15898
15899         function selection_interrupt (name) {
15900           return this.each(function () {
15901             interrupt(this, name);
15902           });
15903         }
15904
15905         function tweenRemove(id, name) {
15906           var tween0, tween1;
15907           return function () {
15908             var schedule = set(this, id),
15909                 tween = schedule.tween; // If this node shared tween with the previous node,
15910             // just assign the updated shared tween and we’re done!
15911             // Otherwise, copy-on-write.
15912
15913             if (tween !== tween0) {
15914               tween1 = tween0 = tween;
15915
15916               for (var i = 0, n = tween1.length; i < n; ++i) {
15917                 if (tween1[i].name === name) {
15918                   tween1 = tween1.slice();
15919                   tween1.splice(i, 1);
15920                   break;
15921                 }
15922               }
15923             }
15924
15925             schedule.tween = tween1;
15926           };
15927         }
15928
15929         function tweenFunction(id, name, value) {
15930           var tween0, tween1;
15931           if (typeof value !== "function") throw new Error();
15932           return function () {
15933             var schedule = set(this, id),
15934                 tween = schedule.tween; // If this node shared tween with the previous node,
15935             // just assign the updated shared tween and we’re done!
15936             // Otherwise, copy-on-write.
15937
15938             if (tween !== tween0) {
15939               tween1 = (tween0 = tween).slice();
15940
15941               for (var t = {
15942                 name: name,
15943                 value: value
15944               }, i = 0, n = tween1.length; i < n; ++i) {
15945                 if (tween1[i].name === name) {
15946                   tween1[i] = t;
15947                   break;
15948                 }
15949               }
15950
15951               if (i === n) tween1.push(t);
15952             }
15953
15954             schedule.tween = tween1;
15955           };
15956         }
15957
15958         function transition_tween (name, value) {
15959           var id = this._id;
15960           name += "";
15961
15962           if (arguments.length < 2) {
15963             var tween = get$1(this.node(), id).tween;
15964
15965             for (var i = 0, n = tween.length, t; i < n; ++i) {
15966               if ((t = tween[i]).name === name) {
15967                 return t.value;
15968               }
15969             }
15970
15971             return null;
15972           }
15973
15974           return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
15975         }
15976         function tweenValue(transition, name, value) {
15977           var id = transition._id;
15978           transition.each(function () {
15979             var schedule = set(this, id);
15980             (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
15981           });
15982           return function (node) {
15983             return get$1(node, id).value[name];
15984           };
15985         }
15986
15987         function interpolate (a, b) {
15988           var c;
15989           return (typeof b === "number" ? d3_interpolateNumber : b instanceof color ? d3_interpolateRgb : (c = color(b)) ? (b = c, d3_interpolateRgb) : interpolateString)(a, b);
15990         }
15991
15992         function attrRemove(name) {
15993           return function () {
15994             this.removeAttribute(name);
15995           };
15996         }
15997
15998         function attrRemoveNS(fullname) {
15999           return function () {
16000             this.removeAttributeNS(fullname.space, fullname.local);
16001           };
16002         }
16003
16004         function attrConstant(name, interpolate, value1) {
16005           var string00,
16006               string1 = value1 + "",
16007               interpolate0;
16008           return function () {
16009             var string0 = this.getAttribute(name);
16010             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
16011           };
16012         }
16013
16014         function attrConstantNS(fullname, interpolate, value1) {
16015           var string00,
16016               string1 = value1 + "",
16017               interpolate0;
16018           return function () {
16019             var string0 = this.getAttributeNS(fullname.space, fullname.local);
16020             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
16021           };
16022         }
16023
16024         function attrFunction(name, interpolate, value) {
16025           var string00, string10, interpolate0;
16026           return function () {
16027             var string0,
16028                 value1 = value(this),
16029                 string1;
16030             if (value1 == null) return void this.removeAttribute(name);
16031             string0 = this.getAttribute(name);
16032             string1 = value1 + "";
16033             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16034           };
16035         }
16036
16037         function attrFunctionNS(fullname, interpolate, value) {
16038           var string00, string10, interpolate0;
16039           return function () {
16040             var string0,
16041                 value1 = value(this),
16042                 string1;
16043             if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
16044             string0 = this.getAttributeNS(fullname.space, fullname.local);
16045             string1 = value1 + "";
16046             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16047           };
16048         }
16049
16050         function transition_attr (name, value) {
16051           var fullname = namespace(name),
16052               i = fullname === "transform" ? interpolateTransformSvg : interpolate;
16053           return this.attrTween(name, typeof value === "function" ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, "attr." + name, value)) : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname) : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value));
16054         }
16055
16056         function attrInterpolate(name, i) {
16057           return function (t) {
16058             this.setAttribute(name, i.call(this, t));
16059           };
16060         }
16061
16062         function attrInterpolateNS(fullname, i) {
16063           return function (t) {
16064             this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));
16065           };
16066         }
16067
16068         function attrTweenNS(fullname, value) {
16069           var t0, i0;
16070
16071           function tween() {
16072             var i = value.apply(this, arguments);
16073             if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);
16074             return t0;
16075           }
16076
16077           tween._value = value;
16078           return tween;
16079         }
16080
16081         function attrTween(name, value) {
16082           var t0, i0;
16083
16084           function tween() {
16085             var i = value.apply(this, arguments);
16086             if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);
16087             return t0;
16088           }
16089
16090           tween._value = value;
16091           return tween;
16092         }
16093
16094         function transition_attrTween (name, value) {
16095           var key = "attr." + name;
16096           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
16097           if (value == null) return this.tween(key, null);
16098           if (typeof value !== "function") throw new Error();
16099           var fullname = namespace(name);
16100           return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
16101         }
16102
16103         function delayFunction(id, value) {
16104           return function () {
16105             init(this, id).delay = +value.apply(this, arguments);
16106           };
16107         }
16108
16109         function delayConstant(id, value) {
16110           return value = +value, function () {
16111             init(this, id).delay = value;
16112           };
16113         }
16114
16115         function transition_delay (value) {
16116           var id = this._id;
16117           return arguments.length ? this.each((typeof value === "function" ? delayFunction : delayConstant)(id, value)) : get$1(this.node(), id).delay;
16118         }
16119
16120         function durationFunction(id, value) {
16121           return function () {
16122             set(this, id).duration = +value.apply(this, arguments);
16123           };
16124         }
16125
16126         function durationConstant(id, value) {
16127           return value = +value, function () {
16128             set(this, id).duration = value;
16129           };
16130         }
16131
16132         function transition_duration (value) {
16133           var id = this._id;
16134           return arguments.length ? this.each((typeof value === "function" ? durationFunction : durationConstant)(id, value)) : get$1(this.node(), id).duration;
16135         }
16136
16137         function easeConstant(id, value) {
16138           if (typeof value !== "function") throw new Error();
16139           return function () {
16140             set(this, id).ease = value;
16141           };
16142         }
16143
16144         function transition_ease (value) {
16145           var id = this._id;
16146           return arguments.length ? this.each(easeConstant(id, value)) : get$1(this.node(), id).ease;
16147         }
16148
16149         function easeVarying(id, value) {
16150           return function () {
16151             var v = value.apply(this, arguments);
16152             if (typeof v !== "function") throw new Error();
16153             set(this, id).ease = v;
16154           };
16155         }
16156
16157         function transition_easeVarying (value) {
16158           if (typeof value !== "function") throw new Error();
16159           return this.each(easeVarying(this._id, value));
16160         }
16161
16162         function transition_filter (match) {
16163           if (typeof match !== "function") match = matcher(match);
16164
16165           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
16166             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
16167               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
16168                 subgroup.push(node);
16169               }
16170             }
16171           }
16172
16173           return new Transition(subgroups, this._parents, this._name, this._id);
16174         }
16175
16176         function transition_merge (transition) {
16177           if (transition._id !== this._id) throw new Error();
16178
16179           for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
16180             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
16181               if (node = group0[i] || group1[i]) {
16182                 merge[i] = node;
16183               }
16184             }
16185           }
16186
16187           for (; j < m0; ++j) {
16188             merges[j] = groups0[j];
16189           }
16190
16191           return new Transition(merges, this._parents, this._name, this._id);
16192         }
16193
16194         function start(name) {
16195           return (name + "").trim().split(/^|\s+/).every(function (t) {
16196             var i = t.indexOf(".");
16197             if (i >= 0) t = t.slice(0, i);
16198             return !t || t === "start";
16199           });
16200         }
16201
16202         function onFunction(id, name, listener) {
16203           var on0,
16204               on1,
16205               sit = start(name) ? init : set;
16206           return function () {
16207             var schedule = sit(this, id),
16208                 on = schedule.on; // If this node shared a dispatch with the previous node,
16209             // just assign the updated shared dispatch and we’re done!
16210             // Otherwise, copy-on-write.
16211
16212             if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
16213             schedule.on = on1;
16214           };
16215         }
16216
16217         function transition_on (name, listener) {
16218           var id = this._id;
16219           return arguments.length < 2 ? get$1(this.node(), id).on.on(name) : this.each(onFunction(id, name, listener));
16220         }
16221
16222         function removeFunction(id) {
16223           return function () {
16224             var parent = this.parentNode;
16225
16226             for (var i in this.__transition) {
16227               if (+i !== id) return;
16228             }
16229
16230             if (parent) parent.removeChild(this);
16231           };
16232         }
16233
16234         function transition_remove () {
16235           return this.on("end.remove", removeFunction(this._id));
16236         }
16237
16238         function transition_select (select) {
16239           var name = this._name,
16240               id = this._id;
16241           if (typeof select !== "function") select = selector(select);
16242
16243           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
16244             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
16245               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
16246                 if ("__data__" in node) subnode.__data__ = node.__data__;
16247                 subgroup[i] = subnode;
16248                 schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
16249               }
16250             }
16251           }
16252
16253           return new Transition(subgroups, this._parents, name, id);
16254         }
16255
16256         function transition_selectAll (select) {
16257           var name = this._name,
16258               id = this._id;
16259           if (typeof select !== "function") select = selectorAll(select);
16260
16261           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
16262             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16263               if (node = group[i]) {
16264                 for (var children = select.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) {
16265                   if (child = children[k]) {
16266                     schedule(child, name, id, k, children, inherit);
16267                   }
16268                 }
16269
16270                 subgroups.push(children);
16271                 parents.push(node);
16272               }
16273             }
16274           }
16275
16276           return new Transition(subgroups, parents, name, id);
16277         }
16278
16279         var Selection = selection.prototype.constructor;
16280         function transition_selection () {
16281           return new Selection(this._groups, this._parents);
16282         }
16283
16284         function styleNull(name, interpolate) {
16285           var string00, string10, interpolate0;
16286           return function () {
16287             var string0 = styleValue(this, name),
16288                 string1 = (this.style.removeProperty(name), styleValue(this, name));
16289             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : interpolate0 = interpolate(string00 = string0, string10 = string1);
16290           };
16291         }
16292
16293         function styleRemove(name) {
16294           return function () {
16295             this.style.removeProperty(name);
16296           };
16297         }
16298
16299         function styleConstant(name, interpolate, value1) {
16300           var string00,
16301               string1 = value1 + "",
16302               interpolate0;
16303           return function () {
16304             var string0 = styleValue(this, name);
16305             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
16306           };
16307         }
16308
16309         function styleFunction(name, interpolate, value) {
16310           var string00, string10, interpolate0;
16311           return function () {
16312             var string0 = styleValue(this, name),
16313                 value1 = value(this),
16314                 string1 = value1 + "";
16315             if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
16316             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16317           };
16318         }
16319
16320         function styleMaybeRemove(id, name) {
16321           var on0,
16322               on1,
16323               listener0,
16324               key = "style." + name,
16325               event = "end." + key,
16326               remove;
16327           return function () {
16328             var schedule = set(this, id),
16329                 on = schedule.on,
16330                 listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : undefined; // If this node shared a dispatch with the previous node,
16331             // just assign the updated shared dispatch and we’re done!
16332             // Otherwise, copy-on-write.
16333
16334             if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
16335             schedule.on = on1;
16336           };
16337         }
16338
16339         function transition_style (name, value, priority) {
16340           var i = (name += "") === "transform" ? interpolateTransformCss : interpolate;
16341           return value == null ? this.styleTween(name, styleNull(name, i)).on("end.style." + name, styleRemove(name)) : typeof value === "function" ? this.styleTween(name, styleFunction(name, i, tweenValue(this, "style." + name, value))).each(styleMaybeRemove(this._id, name)) : this.styleTween(name, styleConstant(name, i, value), priority).on("end.style." + name, null);
16342         }
16343
16344         function styleInterpolate(name, i, priority) {
16345           return function (t) {
16346             this.style.setProperty(name, i.call(this, t), priority);
16347           };
16348         }
16349
16350         function styleTween(name, value, priority) {
16351           var t, i0;
16352
16353           function tween() {
16354             var i = value.apply(this, arguments);
16355             if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);
16356             return t;
16357           }
16358
16359           tween._value = value;
16360           return tween;
16361         }
16362
16363         function transition_styleTween (name, value, priority) {
16364           var key = "style." + (name += "");
16365           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
16366           if (value == null) return this.tween(key, null);
16367           if (typeof value !== "function") throw new Error();
16368           return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
16369         }
16370
16371         function textConstant(value) {
16372           return function () {
16373             this.textContent = value;
16374           };
16375         }
16376
16377         function textFunction(value) {
16378           return function () {
16379             var value1 = value(this);
16380             this.textContent = value1 == null ? "" : value1;
16381           };
16382         }
16383
16384         function transition_text (value) {
16385           return this.tween("text", typeof value === "function" ? textFunction(tweenValue(this, "text", value)) : textConstant(value == null ? "" : value + ""));
16386         }
16387
16388         function textInterpolate(i) {
16389           return function (t) {
16390             this.textContent = i.call(this, t);
16391           };
16392         }
16393
16394         function textTween(value) {
16395           var t0, i0;
16396
16397           function tween() {
16398             var i = value.apply(this, arguments);
16399             if (i !== i0) t0 = (i0 = i) && textInterpolate(i);
16400             return t0;
16401           }
16402
16403           tween._value = value;
16404           return tween;
16405         }
16406
16407         function transition_textTween (value) {
16408           var key = "text";
16409           if (arguments.length < 1) return (key = this.tween(key)) && key._value;
16410           if (value == null) return this.tween(key, null);
16411           if (typeof value !== "function") throw new Error();
16412           return this.tween(key, textTween(value));
16413         }
16414
16415         function transition_transition () {
16416           var name = this._name,
16417               id0 = this._id,
16418               id1 = newId();
16419
16420           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
16421             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16422               if (node = group[i]) {
16423                 var inherit = get$1(node, id0);
16424                 schedule(node, name, id1, i, group, {
16425                   time: inherit.time + inherit.delay + inherit.duration,
16426                   delay: 0,
16427                   duration: inherit.duration,
16428                   ease: inherit.ease
16429                 });
16430               }
16431             }
16432           }
16433
16434           return new Transition(groups, this._parents, name, id1);
16435         }
16436
16437         function transition_end () {
16438           var on0,
16439               on1,
16440               that = this,
16441               id = that._id,
16442               size = that.size();
16443           return new Promise(function (resolve, reject) {
16444             var cancel = {
16445               value: reject
16446             },
16447                 end = {
16448               value: function value() {
16449                 if (--size === 0) resolve();
16450               }
16451             };
16452             that.each(function () {
16453               var schedule = set(this, id),
16454                   on = schedule.on; // If this node shared a dispatch with the previous node,
16455               // just assign the updated shared dispatch and we’re done!
16456               // Otherwise, copy-on-write.
16457
16458               if (on !== on0) {
16459                 on1 = (on0 = on).copy();
16460
16461                 on1._.cancel.push(cancel);
16462
16463                 on1._.interrupt.push(cancel);
16464
16465                 on1._.end.push(end);
16466               }
16467
16468               schedule.on = on1;
16469             }); // The selection was empty, resolve end immediately
16470
16471             if (size === 0) resolve();
16472           });
16473         }
16474
16475         var id = 0;
16476         function Transition(groups, parents, name, id) {
16477           this._groups = groups;
16478           this._parents = parents;
16479           this._name = name;
16480           this._id = id;
16481         }
16482         function newId() {
16483           return ++id;
16484         }
16485         var selection_prototype = selection.prototype;
16486         Transition.prototype = _defineProperty({
16487           constructor: Transition,
16488           select: transition_select,
16489           selectAll: transition_selectAll,
16490           filter: transition_filter,
16491           merge: transition_merge,
16492           selection: transition_selection,
16493           transition: transition_transition,
16494           call: selection_prototype.call,
16495           nodes: selection_prototype.nodes,
16496           node: selection_prototype.node,
16497           size: selection_prototype.size,
16498           empty: selection_prototype.empty,
16499           each: selection_prototype.each,
16500           on: transition_on,
16501           attr: transition_attr,
16502           attrTween: transition_attrTween,
16503           style: transition_style,
16504           styleTween: transition_styleTween,
16505           text: transition_text,
16506           textTween: transition_textTween,
16507           remove: transition_remove,
16508           tween: transition_tween,
16509           delay: transition_delay,
16510           duration: transition_duration,
16511           ease: transition_ease,
16512           easeVarying: transition_easeVarying,
16513           end: transition_end
16514         }, Symbol.iterator, selection_prototype[Symbol.iterator]);
16515
16516         var linear$1 = function linear(t) {
16517           return +t;
16518         };
16519
16520         function cubicInOut(t) {
16521           return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
16522         }
16523
16524         var defaultTiming = {
16525           time: null,
16526           // Set on use.
16527           delay: 0,
16528           duration: 250,
16529           ease: cubicInOut
16530         };
16531
16532         function inherit(node, id) {
16533           var timing;
16534
16535           while (!(timing = node.__transition) || !(timing = timing[id])) {
16536             if (!(node = node.parentNode)) {
16537               throw new Error("transition ".concat(id, " not found"));
16538             }
16539           }
16540
16541           return timing;
16542         }
16543
16544         function selection_transition (name) {
16545           var id, timing;
16546
16547           if (name instanceof Transition) {
16548             id = name._id, name = name._name;
16549           } else {
16550             id = newId(), (timing = defaultTiming).time = now$1(), name = name == null ? null : name + "";
16551           }
16552
16553           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
16554             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16555               if (node = group[i]) {
16556                 schedule(node, name, id, i, group, timing || inherit(node, id));
16557               }
16558             }
16559           }
16560
16561           return new Transition(groups, this._parents, name, id);
16562         }
16563
16564         selection.prototype.interrupt = selection_interrupt;
16565         selection.prototype.transition = selection_transition;
16566
16567         var constant = (function (x) {
16568           return function () {
16569             return x;
16570           };
16571         });
16572
16573         function ZoomEvent(type, _ref) {
16574           var sourceEvent = _ref.sourceEvent,
16575               target = _ref.target,
16576               transform = _ref.transform,
16577               dispatch = _ref.dispatch;
16578           Object.defineProperties(this, {
16579             type: {
16580               value: type,
16581               enumerable: true,
16582               configurable: true
16583             },
16584             sourceEvent: {
16585               value: sourceEvent,
16586               enumerable: true,
16587               configurable: true
16588             },
16589             target: {
16590               value: target,
16591               enumerable: true,
16592               configurable: true
16593             },
16594             transform: {
16595               value: transform,
16596               enumerable: true,
16597               configurable: true
16598             },
16599             _: {
16600               value: dispatch
16601             }
16602           });
16603         }
16604
16605         function Transform(k, x, y) {
16606           this.k = k;
16607           this.x = x;
16608           this.y = y;
16609         }
16610         Transform.prototype = {
16611           constructor: Transform,
16612           scale: function scale(k) {
16613             return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
16614           },
16615           translate: function translate(x, y) {
16616             return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
16617           },
16618           apply: function apply(point) {
16619             return [point[0] * this.k + this.x, point[1] * this.k + this.y];
16620           },
16621           applyX: function applyX(x) {
16622             return x * this.k + this.x;
16623           },
16624           applyY: function applyY(y) {
16625             return y * this.k + this.y;
16626           },
16627           invert: function invert(location) {
16628             return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
16629           },
16630           invertX: function invertX(x) {
16631             return (x - this.x) / this.k;
16632           },
16633           invertY: function invertY(y) {
16634             return (y - this.y) / this.k;
16635           },
16636           rescaleX: function rescaleX(x) {
16637             return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
16638           },
16639           rescaleY: function rescaleY(y) {
16640             return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
16641           },
16642           toString: function toString() {
16643             return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
16644           }
16645         };
16646         var identity$2 = new Transform(1, 0, 0);
16647
16648         function nopropagation(event) {
16649           event.stopImmediatePropagation();
16650         }
16651         function noevent (event) {
16652           event.preventDefault();
16653           event.stopImmediatePropagation();
16654         }
16655
16656         // except for pinch-to-zoom, which is sent as a wheel+ctrlKey event
16657
16658         function defaultFilter$1(event) {
16659           return (!event.ctrlKey || event.type === 'wheel') && !event.button;
16660         }
16661
16662         function defaultExtent$1() {
16663           var e = this;
16664
16665           if (e instanceof SVGElement) {
16666             e = e.ownerSVGElement || e;
16667
16668             if (e.hasAttribute("viewBox")) {
16669               e = e.viewBox.baseVal;
16670               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
16671             }
16672
16673             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
16674           }
16675
16676           return [[0, 0], [e.clientWidth, e.clientHeight]];
16677         }
16678
16679         function defaultTransform() {
16680           return this.__zoom || identity$2;
16681         }
16682
16683         function defaultWheelDelta$1(event) {
16684           return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1);
16685         }
16686
16687         function defaultTouchable() {
16688           return navigator.maxTouchPoints || "ontouchstart" in this;
16689         }
16690
16691         function defaultConstrain$1(transform, extent, translateExtent) {
16692           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
16693               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
16694               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
16695               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
16696           return transform.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));
16697         }
16698
16699         function d3_zoom () {
16700           var filter = defaultFilter$1,
16701               extent = defaultExtent$1,
16702               constrain = defaultConstrain$1,
16703               wheelDelta = defaultWheelDelta$1,
16704               touchable = defaultTouchable,
16705               scaleExtent = [0, Infinity],
16706               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
16707               duration = 250,
16708               interpolate = interpolateZoom,
16709               listeners = dispatch$8("start", "zoom", "end"),
16710               touchstarting,
16711               touchfirst,
16712               touchending,
16713               touchDelay = 500,
16714               wheelDelay = 150,
16715               clickDistance2 = 0,
16716               tapDistance = 10;
16717
16718           function zoom(selection) {
16719             selection.property("__zoom", defaultTransform).on("wheel.zoom", wheeled).on("mousedown.zoom", mousedowned).on("dblclick.zoom", dblclicked).filter(touchable).on("touchstart.zoom", touchstarted).on("touchmove.zoom", touchmoved).on("touchend.zoom touchcancel.zoom", touchended).style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
16720           }
16721
16722           zoom.transform = function (collection, transform, point, event) {
16723             var selection = collection.selection ? collection.selection() : collection;
16724             selection.property("__zoom", defaultTransform);
16725
16726             if (collection !== selection) {
16727               schedule(collection, transform, point, event);
16728             } else {
16729               selection.interrupt().each(function () {
16730                 gesture(this, arguments).event(event).start().zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform).end();
16731               });
16732             }
16733           };
16734
16735           zoom.scaleBy = function (selection, k, p, event) {
16736             zoom.scaleTo(selection, function () {
16737               var k0 = this.__zoom.k,
16738                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
16739               return k0 * k1;
16740             }, p, event);
16741           };
16742
16743           zoom.scaleTo = function (selection, k, p, event) {
16744             zoom.transform(selection, function () {
16745               var e = extent.apply(this, arguments),
16746                   t0 = this.__zoom,
16747                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p,
16748                   p1 = t0.invert(p0),
16749                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
16750               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
16751             }, p, event);
16752           };
16753
16754           zoom.translateBy = function (selection, x, y, event) {
16755             zoom.transform(selection, function () {
16756               return constrain(this.__zoom.translate(typeof x === "function" ? x.apply(this, arguments) : x, typeof y === "function" ? y.apply(this, arguments) : y), extent.apply(this, arguments), translateExtent);
16757             }, null, event);
16758           };
16759
16760           zoom.translateTo = function (selection, x, y, p, event) {
16761             zoom.transform(selection, function () {
16762               var e = extent.apply(this, arguments),
16763                   t = this.__zoom,
16764                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
16765               return constrain(identity$2.translate(p0[0], p0[1]).scale(t.k).translate(typeof x === "function" ? -x.apply(this, arguments) : -x, typeof y === "function" ? -y.apply(this, arguments) : -y), e, translateExtent);
16766             }, p, event);
16767           };
16768
16769           function scale(transform, k) {
16770             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
16771             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
16772           }
16773
16774           function translate(transform, p0, p1) {
16775             var x = p0[0] - p1[0] * transform.k,
16776                 y = p0[1] - p1[1] * transform.k;
16777             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
16778           }
16779
16780           function centroid(extent) {
16781             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
16782           }
16783
16784           function schedule(transition, transform, point, event) {
16785             transition.on("start.zoom", function () {
16786               gesture(this, arguments).event(event).start();
16787             }).on("interrupt.zoom end.zoom", function () {
16788               gesture(this, arguments).event(event).end();
16789             }).tween("zoom", function () {
16790               var that = this,
16791                   args = arguments,
16792                   g = gesture(that, args).event(event),
16793                   e = extent.apply(that, args),
16794                   p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point,
16795                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
16796                   a = that.__zoom,
16797                   b = typeof transform === "function" ? transform.apply(that, args) : transform,
16798                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
16799               return function (t) {
16800                 if (t === 1) t = b; // Avoid rounding error on end.
16801                 else {
16802                     var l = i(t),
16803                         k = w / l[2];
16804                     t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
16805                   }
16806                 g.zoom(null, t);
16807               };
16808             });
16809           }
16810
16811           function gesture(that, args, clean) {
16812             return !clean && that.__zooming || new Gesture(that, args);
16813           }
16814
16815           function Gesture(that, args) {
16816             this.that = that;
16817             this.args = args;
16818             this.active = 0;
16819             this.sourceEvent = null;
16820             this.extent = extent.apply(that, args);
16821             this.taps = 0;
16822           }
16823
16824           Gesture.prototype = {
16825             event: function event(_event) {
16826               if (_event) this.sourceEvent = _event;
16827               return this;
16828             },
16829             start: function start() {
16830               if (++this.active === 1) {
16831                 this.that.__zooming = this;
16832                 this.emit("start");
16833               }
16834
16835               return this;
16836             },
16837             zoom: function zoom(key, transform) {
16838               if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
16839               if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
16840               if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
16841               this.that.__zoom = transform;
16842               this.emit("zoom");
16843               return this;
16844             },
16845             end: function end() {
16846               if (--this.active === 0) {
16847                 delete this.that.__zooming;
16848                 this.emit("end");
16849               }
16850
16851               return this;
16852             },
16853             emit: function emit(type) {
16854               var d = select(this.that).datum();
16855               listeners.call(type, this.that, new ZoomEvent(type, {
16856                 sourceEvent: this.sourceEvent,
16857                 target: zoom,
16858                 type: type,
16859                 transform: this.that.__zoom,
16860                 dispatch: listeners
16861               }), d);
16862             }
16863           };
16864
16865           function wheeled(event) {
16866             for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
16867               args[_key - 1] = arguments[_key];
16868             }
16869
16870             if (!filter.apply(this, arguments)) return;
16871             var g = gesture(this, args).event(event),
16872                 t = this.__zoom,
16873                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
16874                 p = pointer(event); // If the mouse is in the same location as before, reuse it.
16875             // If there were recent wheel events, reset the wheel idle timeout.
16876
16877             if (g.wheel) {
16878               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
16879                 g.mouse[1] = t.invert(g.mouse[0] = p);
16880               }
16881
16882               clearTimeout(g.wheel);
16883             } // If this wheel event won’t trigger a transform change, ignore it.
16884             else if (t.k === k) return; // Otherwise, capture the mouse point and location at the start.
16885               else {
16886                   g.mouse = [p, t.invert(p)];
16887                   interrupt(this);
16888                   g.start();
16889                 }
16890
16891             noevent(event);
16892             g.wheel = setTimeout(wheelidled, wheelDelay);
16893             g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
16894
16895             function wheelidled() {
16896               g.wheel = null;
16897               g.end();
16898             }
16899           }
16900
16901           function mousedowned(event) {
16902             for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
16903               args[_key2 - 1] = arguments[_key2];
16904             }
16905
16906             if (touchending || !filter.apply(this, arguments)) return;
16907             var g = gesture(this, args, true).event(event),
16908                 v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
16909                 p = pointer(event, currentTarget),
16910                 currentTarget = event.currentTarget,
16911                 x0 = event.clientX,
16912                 y0 = event.clientY;
16913             dragDisable(event.view);
16914             nopropagation(event);
16915             g.mouse = [p, this.__zoom.invert(p)];
16916             interrupt(this);
16917             g.start();
16918
16919             function mousemoved(event) {
16920               noevent(event);
16921
16922               if (!g.moved) {
16923                 var dx = event.clientX - x0,
16924                     dy = event.clientY - y0;
16925                 g.moved = dx * dx + dy * dy > clickDistance2;
16926               }
16927
16928               g.event(event).zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent));
16929             }
16930
16931             function mouseupped(event) {
16932               v.on("mousemove.zoom mouseup.zoom", null);
16933               yesdrag(event.view, g.moved);
16934               noevent(event);
16935               g.event(event).end();
16936             }
16937           }
16938
16939           function dblclicked(event) {
16940             for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
16941               args[_key3 - 1] = arguments[_key3];
16942             }
16943
16944             if (!filter.apply(this, arguments)) return;
16945             var t0 = this.__zoom,
16946                 p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this),
16947                 p1 = t0.invert(p0),
16948                 k1 = t0.k * (event.shiftKey ? 0.5 : 2),
16949                 t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);
16950             noevent(event);
16951             if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0, event);else select(this).call(zoom.transform, t1, p0, event);
16952           }
16953
16954           function touchstarted(event) {
16955             for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
16956               args[_key4 - 1] = arguments[_key4];
16957             }
16958
16959             if (!filter.apply(this, arguments)) return;
16960             var touches = event.touches,
16961                 n = touches.length,
16962                 g = gesture(this, args, event.changedTouches.length === n).event(event),
16963                 started,
16964                 i,
16965                 t,
16966                 p;
16967             nopropagation(event);
16968
16969             for (i = 0; i < n; ++i) {
16970               t = touches[i], p = pointer(t, this);
16971               p = [p, this.__zoom.invert(p), t.identifier];
16972               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;
16973             }
16974
16975             if (touchstarting) touchstarting = clearTimeout(touchstarting);
16976
16977             if (started) {
16978               if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function () {
16979                 touchstarting = null;
16980               }, touchDelay);
16981               interrupt(this);
16982               g.start();
16983             }
16984           }
16985
16986           function touchmoved(event) {
16987             if (!this.__zooming) return;
16988
16989             for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
16990               args[_key5 - 1] = arguments[_key5];
16991             }
16992
16993             var g = gesture(this, args).event(event),
16994                 touches = event.changedTouches,
16995                 n = touches.length,
16996                 i,
16997                 t,
16998                 p,
16999                 l;
17000             noevent(event);
17001
17002             for (i = 0; i < n; ++i) {
17003               t = touches[i], p = pointer(t, this);
17004               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;
17005             }
17006
17007             t = g.that.__zoom;
17008
17009             if (g.touch1) {
17010               var p0 = g.touch0[0],
17011                   l0 = g.touch0[1],
17012                   p1 = g.touch1[0],
17013                   l1 = g.touch1[1],
17014                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
17015                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
17016               t = scale(t, Math.sqrt(dp / dl));
17017               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
17018               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
17019             } else if (g.touch0) p = g.touch0[0], l = g.touch0[1];else return;
17020
17021             g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent));
17022           }
17023
17024           function touchended(event) {
17025             for (var _len6 = arguments.length, args = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
17026               args[_key6 - 1] = arguments[_key6];
17027             }
17028
17029             if (!this.__zooming) return;
17030             var g = gesture(this, args).event(event),
17031                 touches = event.changedTouches,
17032                 n = touches.length,
17033                 i,
17034                 t;
17035             nopropagation(event);
17036             if (touchending) clearTimeout(touchending);
17037             touchending = setTimeout(function () {
17038               touchending = null;
17039             }, touchDelay);
17040
17041             for (i = 0; i < n; ++i) {
17042               t = touches[i];
17043               if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
17044             }
17045
17046             if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
17047             if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);else {
17048               g.end(); // If this was a dbltap, reroute to the (optional) dblclick.zoom handler.
17049
17050               if (g.taps === 2) {
17051                 t = pointer(t, this);
17052
17053                 if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {
17054                   var p = select(this).on("dblclick.zoom");
17055                   if (p) p.apply(this, arguments);
17056                 }
17057               }
17058             }
17059           }
17060
17061           zoom.wheelDelta = function (_) {
17062             return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant(+_), zoom) : wheelDelta;
17063           };
17064
17065           zoom.filter = function (_) {
17066             return arguments.length ? (filter = typeof _ === "function" ? _ : constant(!!_), zoom) : filter;
17067           };
17068
17069           zoom.touchable = function (_) {
17070             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant(!!_), zoom) : touchable;
17071           };
17072
17073           zoom.extent = function (_) {
17074             return arguments.length ? (extent = typeof _ === "function" ? _ : constant([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
17075           };
17076
17077           zoom.scaleExtent = function (_) {
17078             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
17079           };
17080
17081           zoom.translateExtent = function (_) {
17082             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]]];
17083           };
17084
17085           zoom.constrain = function (_) {
17086             return arguments.length ? (constrain = _, zoom) : constrain;
17087           };
17088
17089           zoom.duration = function (_) {
17090             return arguments.length ? (duration = +_, zoom) : duration;
17091           };
17092
17093           zoom.interpolate = function (_) {
17094             return arguments.length ? (interpolate = _, zoom) : interpolate;
17095           };
17096
17097           zoom.on = function () {
17098             var value = listeners.on.apply(listeners, arguments);
17099             return value === listeners ? zoom : value;
17100           };
17101
17102           zoom.clickDistance = function (_) {
17103             return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
17104           };
17105
17106           zoom.tapDistance = function (_) {
17107             return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
17108           };
17109
17110           return zoom;
17111         }
17112
17113         /*
17114             Bypasses features of D3's default projection stream pipeline that are unnecessary:
17115             * Antimeridian clipping
17116             * Spherical rotation
17117             * Resampling
17118         */
17119
17120         function geoRawMercator() {
17121           var project = mercatorRaw;
17122           var k = 512 / Math.PI; // scale
17123
17124           var x = 0;
17125           var y = 0; // translate
17126
17127           var clipExtent = [[0, 0], [0, 0]];
17128
17129           function projection(point) {
17130             point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
17131             return [point[0] * k + x, y - point[1] * k];
17132           }
17133
17134           projection.invert = function (point) {
17135             point = project.invert((point[0] - x) / k, (y - point[1]) / k);
17136             return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
17137           };
17138
17139           projection.scale = function (_) {
17140             if (!arguments.length) return k;
17141             k = +_;
17142             return projection;
17143           };
17144
17145           projection.translate = function (_) {
17146             if (!arguments.length) return [x, y];
17147             x = +_[0];
17148             y = +_[1];
17149             return projection;
17150           };
17151
17152           projection.clipExtent = function (_) {
17153             if (!arguments.length) return clipExtent;
17154             clipExtent = _;
17155             return projection;
17156           };
17157
17158           projection.transform = function (obj) {
17159             if (!arguments.length) return identity$2.translate(x, y).scale(k);
17160             x = +obj.x;
17161             y = +obj.y;
17162             k = +obj.k;
17163             return projection;
17164           };
17165
17166           projection.stream = d3_geoTransform({
17167             point: function point(x, y) {
17168               var vec = projection([x, y]);
17169               this.stream.point(vec[0], vec[1]);
17170             }
17171           }).stream;
17172           return projection;
17173         }
17174
17175         function geoOrthoNormalizedDotProduct(a, b, origin) {
17176           if (geoVecEqual(origin, a) || geoVecEqual(origin, b)) {
17177             return 1; // coincident points, treat as straight and try to remove
17178           }
17179
17180           return geoVecNormalizedDot(a, b, origin);
17181         }
17182
17183         function geoOrthoFilterDotProduct(dotp, epsilon, lowerThreshold, upperThreshold, allowStraightAngles) {
17184           var val = Math.abs(dotp);
17185
17186           if (val < epsilon) {
17187             return 0; // already orthogonal
17188           } else if (allowStraightAngles && Math.abs(val - 1) < epsilon) {
17189             return 0; // straight angle, which is okay in this case
17190           } else if (val < lowerThreshold || val > upperThreshold) {
17191             return dotp; // can be adjusted
17192           } else {
17193             return null; // ignore vertex
17194           }
17195         }
17196
17197         function geoOrthoCalcScore(points, isClosed, epsilon, threshold) {
17198           var score = 0;
17199           var first = isClosed ? 0 : 1;
17200           var last = isClosed ? points.length : points.length - 1;
17201           var coords = points.map(function (p) {
17202             return p.coord;
17203           });
17204           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
17205           var upperThreshold = Math.cos(threshold * Math.PI / 180);
17206
17207           for (var i = first; i < last; i++) {
17208             var a = coords[(i - 1 + coords.length) % coords.length];
17209             var origin = coords[i];
17210             var b = coords[(i + 1) % coords.length];
17211             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold);
17212             if (dotp === null) continue; // ignore vertex
17213
17214             score = score + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
17215           }
17216
17217           return score;
17218         } // returns the maximum angle less than `lessThan` between the actual corner and a 0° or 90° corner
17219
17220         function geoOrthoMaxOffsetAngle(coords, isClosed, lessThan) {
17221           var max = -Infinity;
17222           var first = isClosed ? 0 : 1;
17223           var last = isClosed ? coords.length : coords.length - 1;
17224
17225           for (var i = first; i < last; i++) {
17226             var a = coords[(i - 1 + coords.length) % coords.length];
17227             var origin = coords[i];
17228             var b = coords[(i + 1) % coords.length];
17229             var normalizedDotP = geoOrthoNormalizedDotProduct(a, b, origin);
17230             var angle = Math.acos(Math.abs(normalizedDotP)) * 180 / Math.PI;
17231             if (angle > 45) angle = 90 - angle;
17232             if (angle >= lessThan) continue;
17233             if (angle > max) max = angle;
17234           }
17235
17236           if (max === -Infinity) return null;
17237           return max;
17238         } // similar to geoOrthoCalcScore, but returns quickly if there is something to do
17239
17240         function geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles) {
17241           var score = null;
17242           var first = isClosed ? 0 : 1;
17243           var last = isClosed ? coords.length : coords.length - 1;
17244           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
17245           var upperThreshold = Math.cos(threshold * Math.PI / 180);
17246
17247           for (var i = first; i < last; i++) {
17248             var a = coords[(i - 1 + coords.length) % coords.length];
17249             var origin = coords[i];
17250             var b = coords[(i + 1) % coords.length];
17251             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold, allowStraightAngles);
17252             if (dotp === null) continue; // ignore vertex
17253
17254             if (Math.abs(dotp) > 0) return 1; // something to do
17255
17256             score = 0; // already square
17257           }
17258
17259           return score;
17260         }
17261
17262         var onFreeze = internalMetadata.onFreeze;
17263
17264         // eslint-disable-next-line es/no-object-freeze -- safe
17265         var $freeze = Object.freeze;
17266         var FAILS_ON_PRIMITIVES = fails(function () { $freeze(1); });
17267
17268         // `Object.freeze` method
17269         // https://tc39.es/ecma262/#sec-object.freeze
17270         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES, sham: !freezing }, {
17271           freeze: function freeze(it) {
17272             return $freeze && isObject$4(it) ? $freeze(onFreeze(it)) : it;
17273           }
17274         });
17275
17276         // Returns true if a and b have the same elements at the same indices.
17277         function utilArrayIdentical(a, b) {
17278           // an array is always identical to itself
17279           if (a === b) return true;
17280           var i = a.length;
17281           if (i !== b.length) return false;
17282
17283           while (i--) {
17284             if (a[i] !== b[i]) return false;
17285           }
17286
17287           return true;
17288         } // http://2ality.com/2015/01/es6-set-operations.html
17289         // Difference (a \ b): create a set that contains those elements of set a that are not in set b.
17290         // This operation is also sometimes called minus (-).
17291         // var a = [1,2,3];
17292         // var b = [4,3,2];
17293         // utilArrayDifference(a, b)
17294         //   [1]
17295         // utilArrayDifference(b, a)
17296         //   [4]
17297
17298         function utilArrayDifference(a, b) {
17299           var other = new Set(b);
17300           return Array.from(new Set(a)).filter(function (v) {
17301             return !other.has(v);
17302           });
17303         } // Intersection (a ∩ b): create a set that contains those elements of set a that are also in set b.
17304         // var a = [1,2,3];
17305         // var b = [4,3,2];
17306         // utilArrayIntersection(a, b)
17307         //   [2,3]
17308
17309         function utilArrayIntersection(a, b) {
17310           var other = new Set(b);
17311           return Array.from(new Set(a)).filter(function (v) {
17312             return other.has(v);
17313           });
17314         } // Union (a ∪ b): create a set that contains the elements of both set a and set b.
17315         // var a = [1,2,3];
17316         // var b = [4,3,2];
17317         // utilArrayUnion(a, b)
17318         //   [1,2,3,4]
17319
17320         function utilArrayUnion(a, b) {
17321           var result = new Set(a);
17322           b.forEach(function (v) {
17323             result.add(v);
17324           });
17325           return Array.from(result);
17326         } // Returns an Array with all the duplicates removed
17327         // var a = [1,1,2,3,3];
17328         // utilArrayUniq(a)
17329         //   [1,2,3]
17330
17331         function utilArrayUniq(a) {
17332           return Array.from(new Set(a));
17333         } // Splits array into chunks of given chunk size
17334         // var a = [1,2,3,4,5,6,7];
17335         // utilArrayChunk(a, 3);
17336         //   [[1,2,3],[4,5,6],[7]];
17337
17338         function utilArrayChunk(a, chunkSize) {
17339           if (!chunkSize || chunkSize < 0) return [a.slice()];
17340           var result = new Array(Math.ceil(a.length / chunkSize));
17341           return Array.from(result, function (item, i) {
17342             return a.slice(i * chunkSize, i * chunkSize + chunkSize);
17343           });
17344         } // Flattens two level array into a single level
17345         // var a = [[1,2,3],[4,5,6],[7]];
17346         // utilArrayFlatten(a);
17347         //   [1,2,3,4,5,6,7];
17348
17349         function utilArrayFlatten(a) {
17350           return a.reduce(function (acc, val) {
17351             return acc.concat(val);
17352           }, []);
17353         } // Groups the items of the Array according to the given key
17354         // `key` can be passed as a property or as a key function
17355         //
17356         // var pets = [
17357         //     { type: 'Dog', name: 'Spot' },
17358         //     { type: 'Cat', name: 'Tiger' },
17359         //     { type: 'Dog', name: 'Rover' },
17360         //     { type: 'Cat', name: 'Leo' }
17361         // ];
17362         //
17363         // utilArrayGroupBy(pets, 'type')
17364         //   {
17365         //     'Dog': [{type: 'Dog', name: 'Spot'}, {type: 'Dog', name: 'Rover'}],
17366         //     'Cat': [{type: 'Cat', name: 'Tiger'}, {type: 'Cat', name: 'Leo'}]
17367         //   }
17368         //
17369         // utilArrayGroupBy(pets, function(item) { return item.name.length; })
17370         //   {
17371         //     3: [{type: 'Cat', name: 'Leo'}],
17372         //     4: [{type: 'Dog', name: 'Spot'}],
17373         //     5: [{type: 'Cat', name: 'Tiger'}, {type: 'Dog', name: 'Rover'}]
17374         //   }
17375
17376         function utilArrayGroupBy(a, key) {
17377           return a.reduce(function (acc, item) {
17378             var group = typeof key === 'function' ? key(item) : item[key];
17379             (acc[group] = acc[group] || []).push(item);
17380             return acc;
17381           }, {});
17382         } // Returns an Array with all the duplicates removed
17383         // where uniqueness determined by the given key
17384         // `key` can be passed as a property or as a key function
17385         //
17386         // var pets = [
17387         //     { type: 'Dog', name: 'Spot' },
17388         //     { type: 'Cat', name: 'Tiger' },
17389         //     { type: 'Dog', name: 'Rover' },
17390         //     { type: 'Cat', name: 'Leo' }
17391         // ];
17392         //
17393         // utilArrayUniqBy(pets, 'type')
17394         //   [
17395         //     { type: 'Dog', name: 'Spot' },
17396         //     { type: 'Cat', name: 'Tiger' }
17397         //   ]
17398         //
17399         // utilArrayUniqBy(pets, function(item) { return item.name.length; })
17400         //   [
17401         //     { type: 'Dog', name: 'Spot' },
17402         //     { type: 'Cat', name: 'Tiger' },
17403         //     { type: 'Cat', name: 'Leo' }
17404         //   }
17405
17406         function utilArrayUniqBy(a, key) {
17407           var seen = new Set();
17408           return a.reduce(function (acc, item) {
17409             var val = typeof key === 'function' ? key(item) : item[key];
17410
17411             if (val && !seen.has(val)) {
17412               seen.add(val);
17413               acc.push(item);
17414             }
17415
17416             return acc;
17417           }, []);
17418         }
17419
17420         // @@match logic
17421         fixRegexpWellKnownSymbolLogic('match', function (MATCH, nativeMatch, maybeCallNative) {
17422           return [
17423             // `String.prototype.match` method
17424             // https://tc39.es/ecma262/#sec-string.prototype.match
17425             function match(regexp) {
17426               var O = requireObjectCoercible(this);
17427               var matcher = regexp == undefined ? undefined : regexp[MATCH];
17428               return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
17429             },
17430             // `RegExp.prototype[@@match]` method
17431             // https://tc39.es/ecma262/#sec-regexp.prototype-@@match
17432             function (string) {
17433               var res = maybeCallNative(nativeMatch, this, string);
17434               if (res.done) return res.value;
17435
17436               var rx = anObject(this);
17437               var S = String(string);
17438
17439               if (!rx.global) return regexpExecAbstract(rx, S);
17440
17441               var fullUnicode = rx.unicode;
17442               rx.lastIndex = 0;
17443               var A = [];
17444               var n = 0;
17445               var result;
17446               while ((result = regexpExecAbstract(rx, S)) !== null) {
17447                 var matchStr = String(result[0]);
17448                 A[n] = matchStr;
17449                 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
17450                 n++;
17451               }
17452               return n === 0 ? null : A;
17453             }
17454           ];
17455         });
17456
17457         var remove$6 = removeDiacritics;
17458         var replacementList = [{
17459           base: ' ',
17460           chars: "\xA0"
17461         }, {
17462           base: '0',
17463           chars: "\u07C0"
17464         }, {
17465           base: 'A',
17466           chars: "\u24B6\uFF21\xC0\xC1\xC2\u1EA6\u1EA4\u1EAA\u1EA8\xC3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\xC4\u01DE\u1EA2\xC5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F"
17467         }, {
17468           base: 'AA',
17469           chars: "\uA732"
17470         }, {
17471           base: 'AE',
17472           chars: "\xC6\u01FC\u01E2"
17473         }, {
17474           base: 'AO',
17475           chars: "\uA734"
17476         }, {
17477           base: 'AU',
17478           chars: "\uA736"
17479         }, {
17480           base: 'AV',
17481           chars: "\uA738\uA73A"
17482         }, {
17483           base: 'AY',
17484           chars: "\uA73C"
17485         }, {
17486           base: 'B',
17487           chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181"
17488         }, {
17489           base: 'C',
17490           chars: "\u24B8\uFF23\uA73E\u1E08\u0106C\u0108\u010A\u010C\xC7\u0187\u023B"
17491         }, {
17492           base: 'D',
17493           chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779"
17494         }, {
17495           base: 'Dh',
17496           chars: "\xD0"
17497         }, {
17498           base: 'DZ',
17499           chars: "\u01F1\u01C4"
17500         }, {
17501           base: 'Dz',
17502           chars: "\u01F2\u01C5"
17503         }, {
17504           base: 'E',
17505           chars: "\u025B\u24BA\uFF25\xC8\xC9\xCA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\xCB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E\u1D07"
17506         }, {
17507           base: 'F',
17508           chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B"
17509         }, {
17510           base: 'G',
17511           chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262"
17512         }, {
17513           base: 'H',
17514           chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"
17515         }, {
17516           base: 'I',
17517           chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"
17518         }, {
17519           base: 'J',
17520           chars: "\u24BF\uFF2A\u0134\u0248\u0237"
17521         }, {
17522           base: 'K',
17523           chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"
17524         }, {
17525           base: 'L',
17526           chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"
17527         }, {
17528           base: 'LJ',
17529           chars: "\u01C7"
17530         }, {
17531           base: 'Lj',
17532           chars: "\u01C8"
17533         }, {
17534           base: 'M',
17535           chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB"
17536         }, {
17537           base: 'N',
17538           chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E"
17539         }, {
17540           base: 'NJ',
17541           chars: "\u01CA"
17542         }, {
17543           base: 'Nj',
17544           chars: "\u01CB"
17545         }, {
17546           base: 'O',
17547           chars: "\u24C4\uFF2F\xD2\xD3\xD4\u1ED2\u1ED0\u1ED6\u1ED4\xD5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\xD6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\xD8\u01FE\u0186\u019F\uA74A\uA74C"
17548         }, {
17549           base: 'OE',
17550           chars: "\u0152"
17551         }, {
17552           base: 'OI',
17553           chars: "\u01A2"
17554         }, {
17555           base: 'OO',
17556           chars: "\uA74E"
17557         }, {
17558           base: 'OU',
17559           chars: "\u0222"
17560         }, {
17561           base: 'P',
17562           chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"
17563         }, {
17564           base: 'Q',
17565           chars: "\u24C6\uFF31\uA756\uA758\u024A"
17566         }, {
17567           base: 'R',
17568           chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"
17569         }, {
17570           base: 'S',
17571           chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"
17572         }, {
17573           base: 'T',
17574           chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"
17575         }, {
17576           base: 'Th',
17577           chars: "\xDE"
17578         }, {
17579           base: 'TZ',
17580           chars: "\uA728"
17581         }, {
17582           base: 'U',
17583           chars: "\u24CA\uFF35\xD9\xDA\xDB\u0168\u1E78\u016A\u1E7A\u016C\xDC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244"
17584         }, {
17585           base: 'V',
17586           chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"
17587         }, {
17588           base: 'VY',
17589           chars: "\uA760"
17590         }, {
17591           base: 'W',
17592           chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"
17593         }, {
17594           base: 'X',
17595           chars: "\u24CD\uFF38\u1E8A\u1E8C"
17596         }, {
17597           base: 'Y',
17598           chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"
17599         }, {
17600           base: 'Z',
17601           chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"
17602         }, {
17603           base: 'a',
17604           chars: "\u24D0\uFF41\u1E9A\xE0\xE1\xE2\u1EA7\u1EA5\u1EAB\u1EA9\xE3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\xE4\u01DF\u1EA3\xE5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250\u0251"
17605         }, {
17606           base: 'aa',
17607           chars: "\uA733"
17608         }, {
17609           base: 'ae',
17610           chars: "\xE6\u01FD\u01E3"
17611         }, {
17612           base: 'ao',
17613           chars: "\uA735"
17614         }, {
17615           base: 'au',
17616           chars: "\uA737"
17617         }, {
17618           base: 'av',
17619           chars: "\uA739\uA73B"
17620         }, {
17621           base: 'ay',
17622           chars: "\uA73D"
17623         }, {
17624           base: 'b',
17625           chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182"
17626         }, {
17627           base: 'c',
17628           chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\xE7\u1E09\u0188\u023C\uA73F\u2184"
17629         }, {
17630           base: 'd',
17631           chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA"
17632         }, {
17633           base: 'dh',
17634           chars: "\xF0"
17635         }, {
17636           base: 'dz',
17637           chars: "\u01F3\u01C6"
17638         }, {
17639           base: 'e',
17640           chars: "\u24D4\uFF45\xE8\xE9\xEA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\xEB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u01DD"
17641         }, {
17642           base: 'f',
17643           chars: "\u24D5\uFF46\u1E1F\u0192"
17644         }, {
17645           base: 'ff',
17646           chars: "\uFB00"
17647         }, {
17648           base: 'fi',
17649           chars: "\uFB01"
17650         }, {
17651           base: 'fl',
17652           chars: "\uFB02"
17653         }, {
17654           base: 'ffi',
17655           chars: "\uFB03"
17656         }, {
17657           base: 'ffl',
17658           chars: "\uFB04"
17659         }, {
17660           base: 'g',
17661           chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79"
17662         }, {
17663           base: 'h',
17664           chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"
17665         }, {
17666           base: 'hv',
17667           chars: "\u0195"
17668         }, {
17669           base: 'i',
17670           chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"
17671         }, {
17672           base: 'j',
17673           chars: "\u24D9\uFF4A\u0135\u01F0\u0249"
17674         }, {
17675           base: 'k',
17676           chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"
17677         }, {
17678           base: 'l',
17679           chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D"
17680         }, {
17681           base: 'lj',
17682           chars: "\u01C9"
17683         }, {
17684           base: 'm',
17685           chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"
17686         }, {
17687           base: 'n',
17688           chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509"
17689         }, {
17690           base: 'nj',
17691           chars: "\u01CC"
17692         }, {
17693           base: 'o',
17694           chars: "\u24DE\uFF4F\xF2\xF3\xF4\u1ED3\u1ED1\u1ED7\u1ED5\xF5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\xF6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\xF8\u01FF\uA74B\uA74D\u0275\u0254\u1D11"
17695         }, {
17696           base: 'oe',
17697           chars: "\u0153"
17698         }, {
17699           base: 'oi',
17700           chars: "\u01A3"
17701         }, {
17702           base: 'oo',
17703           chars: "\uA74F"
17704         }, {
17705           base: 'ou',
17706           chars: "\u0223"
17707         }, {
17708           base: 'p',
17709           chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1"
17710         }, {
17711           base: 'q',
17712           chars: "\u24E0\uFF51\u024B\uA757\uA759"
17713         }, {
17714           base: 'r',
17715           chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"
17716         }, {
17717           base: 's',
17718           chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282"
17719         }, {
17720           base: 'ss',
17721           chars: "\xDF"
17722         }, {
17723           base: 't',
17724           chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"
17725         }, {
17726           base: 'th',
17727           chars: "\xFE"
17728         }, {
17729           base: 'tz',
17730           chars: "\uA729"
17731         }, {
17732           base: 'u',
17733           chars: "\u24E4\uFF55\xF9\xFA\xFB\u0169\u1E79\u016B\u1E7B\u016D\xFC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289"
17734         }, {
17735           base: 'v',
17736           chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"
17737         }, {
17738           base: 'vy',
17739           chars: "\uA761"
17740         }, {
17741           base: 'w',
17742           chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"
17743         }, {
17744           base: 'x',
17745           chars: "\u24E7\uFF58\u1E8B\u1E8D"
17746         }, {
17747           base: 'y',
17748           chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"
17749         }, {
17750           base: 'z',
17751           chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"
17752         }];
17753         var diacriticsMap = {};
17754
17755         for (var i$1 = 0; i$1 < replacementList.length; i$1 += 1) {
17756           var chars = replacementList[i$1].chars;
17757
17758           for (var j$1 = 0; j$1 < chars.length; j$1 += 1) {
17759             diacriticsMap[chars[j$1]] = replacementList[i$1].base;
17760           }
17761         }
17762
17763         function removeDiacritics(str) {
17764           return str.replace(/[^\u0000-\u007e]/g, function (c) {
17765             return diacriticsMap[c] || c;
17766           });
17767         }
17768
17769         var replacementList_1 = replacementList;
17770         var diacriticsMap_1 = diacriticsMap;
17771         var diacritics = {
17772           remove: remove$6,
17773           replacementList: replacementList_1,
17774           diacriticsMap: diacriticsMap_1
17775         };
17776
17777         var arabicBlocks = [[0x0600, 0x06FF], [0x0750, 0x077F], [0x08A0, 0x08FF], [0xFB50, 0xFDFF], [0xFE70, 0xFEFF], [0x10E60, 0x10E7F], [0x1EC70, 0x1ECBF], [0x1EE00, 0x1EEFF] // Mathematical Alphabetic symbols https://www.unicode.org/charts/PDF/U1EE00.pdf
17778         ];
17779
17780         function isArabic(_char) {
17781           if (_char.length > 1) {
17782             // allow the newer chars?
17783             throw new Error('isArabic works on only one-character strings');
17784           }
17785
17786           var code = _char.charCodeAt(0);
17787
17788           for (var i = 0; i < arabicBlocks.length; i++) {
17789             var block = arabicBlocks[i];
17790
17791             if (code >= block[0] && code <= block[1]) {
17792               return true;
17793             }
17794           }
17795
17796           return false;
17797         }
17798
17799         var isArabic_2 = isArabic;
17800
17801         function isMath(_char2) {
17802           if (_char2.length > 2) {
17803             // allow the newer chars?
17804             throw new Error('isMath works on only one-character strings');
17805           }
17806
17807           var code = _char2.charCodeAt(0);
17808
17809           return code >= 0x660 && code <= 0x66C || code >= 0x6F0 && code <= 0x6F9;
17810         }
17811
17812         var isMath_1 = isMath;
17813         var isArabic_1 = /*#__PURE__*/Object.defineProperty({
17814           isArabic: isArabic_2,
17815           isMath: isMath_1
17816         }, '__esModule', {
17817           value: true
17818         });
17819
17820         var arabicReference = {
17821           "alef": {
17822             "normal": ["\u0627"],
17823             "madda_above": {
17824               "normal": ["\u0627\u0653", "\u0622"],
17825               "isolated": "\uFE81",
17826               "final": "\uFE82"
17827             },
17828             "hamza_above": {
17829               "normal": ["\u0627\u0654", "\u0623"],
17830               "isolated": "\uFE83",
17831               "final": "\uFE84"
17832             },
17833             "hamza_below": {
17834               "normal": ["\u0627\u0655", "\u0625"],
17835               "isolated": "\uFE87",
17836               "final": "\uFE88"
17837             },
17838             "wasla": {
17839               "normal": "\u0671",
17840               "isolated": "\uFB50",
17841               "final": "\uFB51"
17842             },
17843             "wavy_hamza_above": ["\u0672"],
17844             "wavy_hamza_below": ["\u0627\u065F", "\u0673"],
17845             "high_hamza": ["\u0675", "\u0627\u0674"],
17846             "indic_two_above": ["\u0773"],
17847             "indic_three_above": ["\u0774"],
17848             "fathatan": {
17849               "normal": ["\u0627\u064B"],
17850               "final": "\uFD3C",
17851               "isolated": "\uFD3D"
17852             },
17853             "isolated": "\uFE8D",
17854             "final": "\uFE8E"
17855           },
17856           "beh": {
17857             "normal": ["\u0628"],
17858             "dotless": ["\u066E"],
17859             "three_dots_horizontally_below": ["\u0750"],
17860             "dot_below_three_dots_above": ["\u0751"],
17861             "three_dots_pointing_upwards_below": ["\u0752"],
17862             "three_dots_pointing_upwards_below_two_dots_above": ["\u0753"],
17863             "two_dots_below_dot_above": ["\u0754"],
17864             "inverted_small_v_below": ["\u0755"],
17865             "small_v": ["\u0756"],
17866             "small_v_below": ["\u08A0"],
17867             "hamza_above": ["\u08A1"],
17868             "small_meem_above": ["\u08B6"],
17869             "isolated": "\uFE8F",
17870             "final": "\uFE90",
17871             "initial": "\uFE91",
17872             "medial": "\uFE92"
17873           },
17874           "teh marbuta": {
17875             "normal": ["\u0629"],
17876             "isolated": "\uFE93",
17877             "final": "\uFE94"
17878           },
17879           "teh": {
17880             "normal": ["\u062A"],
17881             "ring": ["\u067C"],
17882             "three_dots_above_downwards": ["\u067D"],
17883             "small_teh_above": ["\u08B8"],
17884             "isolated": "\uFE95",
17885             "final": "\uFE96",
17886             "initial": "\uFE97",
17887             "medial": "\uFE98"
17888           },
17889           "theh": {
17890             "normal": ["\u062B"],
17891             "isolated": "\uFE99",
17892             "final": "\uFE9A",
17893             "initial": "\uFE9B",
17894             "medial": "\uFE9C"
17895           },
17896           "jeem": {
17897             "normal": ["\u062C"],
17898             "two_dots_above": ["\u08A2"],
17899             "isolated": "\uFE9D",
17900             "final": "\uFE9E",
17901             "initial": "\uFE9F",
17902             "medial": "\uFEA0"
17903           },
17904           "hah": {
17905             "normal": ["\u062D"],
17906             "hamza_above": ["\u0681"],
17907             "two_dots_vertical_above": ["\u0682"],
17908             "three_dots_above": ["\u0685"],
17909             "two_dots_above": ["\u0757"],
17910             "three_dots_pointing_upwards_below": ["\u0758"],
17911             "small_tah_below": ["\u076E"],
17912             "small_tah_two_dots": ["\u076F"],
17913             "small_tah_above": ["\u0772"],
17914             "indic_four_below": ["\u077C"],
17915             "isolated": "\uFEA1",
17916             "final": "\uFEA2",
17917             "initial": "\uFEA3",
17918             "medial": "\uFEA4"
17919           },
17920           "khah": {
17921             "normal": ["\u062E"],
17922             "isolated": "\uFEA5",
17923             "final": "\uFEA6",
17924             "initial": "\uFEA7",
17925             "medial": "\uFEA8"
17926           },
17927           "dal": {
17928             "normal": ["\u062F"],
17929             "ring": ["\u0689"],
17930             "dot_below": ["\u068A"],
17931             "dot_below_small_tah": ["\u068B"],
17932             "three_dots_above_downwards": ["\u068F"],
17933             "four_dots_above": ["\u0690"],
17934             "inverted_v": ["\u06EE"],
17935             "two_dots_vertically_below_small_tah": ["\u0759"],
17936             "inverted_small_v_below": ["\u075A"],
17937             "three_dots_below": ["\u08AE"],
17938             "isolated": "\uFEA9",
17939             "final": "\uFEAA"
17940           },
17941           "thal": {
17942             "normal": ["\u0630"],
17943             "isolated": "\uFEAB",
17944             "final": "\uFEAC"
17945           },
17946           "reh": {
17947             "normal": ["\u0631"],
17948             "small_v": ["\u0692"],
17949             "ring": ["\u0693"],
17950             "dot_below": ["\u0694"],
17951             "small_v_below": ["\u0695"],
17952             "dot_below_dot_above": ["\u0696"],
17953             "two_dots_above": ["\u0697"],
17954             "four_dots_above": ["\u0699"],
17955             "inverted_v": ["\u06EF"],
17956             "stroke": ["\u075B"],
17957             "two_dots_vertically_above": ["\u076B"],
17958             "hamza_above": ["\u076C"],
17959             "small_tah_two_dots": ["\u0771"],
17960             "loop": ["\u08AA"],
17961             "small_noon_above": ["\u08B9"],
17962             "isolated": "\uFEAD",
17963             "final": "\uFEAE"
17964           },
17965           "zain": {
17966             "normal": ["\u0632"],
17967             "inverted_v_above": ["\u08B2"],
17968             "isolated": "\uFEAF",
17969             "final": "\uFEB0"
17970           },
17971           "seen": {
17972             "normal": ["\u0633"],
17973             "dot_below_dot_above": ["\u069A"],
17974             "three_dots_below": ["\u069B"],
17975             "three_dots_below_three_dots_above": ["\u069C"],
17976             "four_dots_above": ["\u075C"],
17977             "two_dots_vertically_above": ["\u076D"],
17978             "small_tah_two_dots": ["\u0770"],
17979             "indic_four_above": ["\u077D"],
17980             "inverted_v": ["\u077E"],
17981             "isolated": "\uFEB1",
17982             "final": "\uFEB2",
17983             "initial": "\uFEB3",
17984             "medial": "\uFEB4"
17985           },
17986           "sheen": {
17987             "normal": ["\u0634"],
17988             "dot_below": ["\u06FA"],
17989             "isolated": "\uFEB5",
17990             "final": "\uFEB6",
17991             "initial": "\uFEB7",
17992             "medial": "\uFEB8"
17993           },
17994           "sad": {
17995             "normal": ["\u0635"],
17996             "two_dots_below": ["\u069D"],
17997             "three_dots_above": ["\u069E"],
17998             "three_dots_below": ["\u08AF"],
17999             "isolated": "\uFEB9",
18000             "final": "\uFEBA",
18001             "initial": "\uFEBB",
18002             "medial": "\uFEBC"
18003           },
18004           "dad": {
18005             "normal": ["\u0636"],
18006             "dot_below": ["\u06FB"],
18007             "isolated": "\uFEBD",
18008             "final": "\uFEBE",
18009             "initial": "\uFEBF",
18010             "medial": "\uFEC0"
18011           },
18012           "tah": {
18013             "normal": ["\u0637"],
18014             "three_dots_above": ["\u069F"],
18015             "two_dots_above": ["\u08A3"],
18016             "isolated": "\uFEC1",
18017             "final": "\uFEC2",
18018             "initial": "\uFEC3",
18019             "medial": "\uFEC4"
18020           },
18021           "zah": {
18022             "normal": ["\u0638"],
18023             "isolated": "\uFEC5",
18024             "final": "\uFEC6",
18025             "initial": "\uFEC7",
18026             "medial": "\uFEC8"
18027           },
18028           "ain": {
18029             "normal": ["\u0639"],
18030             "three_dots_above": ["\u06A0"],
18031             "two_dots_above": ["\u075D"],
18032             "three_dots_pointing_downwards_above": ["\u075E"],
18033             "two_dots_vertically_above": ["\u075F"],
18034             "three_dots_below": ["\u08B3"],
18035             "isolated": "\uFEC9",
18036             "final": "\uFECA",
18037             "initial": "\uFECB",
18038             "medial": "\uFECC"
18039           },
18040           "ghain": {
18041             "normal": ["\u063A"],
18042             "dot_below": ["\u06FC"],
18043             "isolated": "\uFECD",
18044             "final": "\uFECE",
18045             "initial": "\uFECF",
18046             "medial": "\uFED0"
18047           },
18048           "feh": {
18049             "normal": ["\u0641"],
18050             "dotless": ["\u06A1"],
18051             "dot_moved_below": ["\u06A2"],
18052             "dot_below": ["\u06A3"],
18053             "three_dots_below": ["\u06A5"],
18054             "two_dots_below": ["\u0760"],
18055             "three_dots_pointing_upwards_below": ["\u0761"],
18056             "dot_below_three_dots_above": ["\u08A4"],
18057             "isolated": "\uFED1",
18058             "final": "\uFED2",
18059             "initial": "\uFED3",
18060             "medial": "\uFED4"
18061           },
18062           "qaf": {
18063             "normal": ["\u0642"],
18064             "dotless": ["\u066F"],
18065             "dot_above": ["\u06A7"],
18066             "three_dots_above": ["\u06A8"],
18067             "dot_below": ["\u08A5"],
18068             "isolated": "\uFED5",
18069             "final": "\uFED6",
18070             "initial": "\uFED7",
18071             "medial": "\uFED8"
18072           },
18073           "kaf": {
18074             "normal": ["\u0643"],
18075             "swash": ["\u06AA"],
18076             "ring": ["\u06AB"],
18077             "dot_above": ["\u06AC"],
18078             "three_dots_below": ["\u06AE"],
18079             "two_dots_above": ["\u077F"],
18080             "dot_below": ["\u08B4"],
18081             "isolated": "\uFED9",
18082             "final": "\uFEDA",
18083             "initial": "\uFEDB",
18084             "medial": "\uFEDC"
18085           },
18086           "lam": {
18087             "normal": ["\u0644"],
18088             "small_v": ["\u06B5"],
18089             "dot_above": ["\u06B6"],
18090             "three_dots_above": ["\u06B7"],
18091             "three_dots_below": ["\u06B8"],
18092             "bar": ["\u076A"],
18093             "double_bar": ["\u08A6"],
18094             "isolated": "\uFEDD",
18095             "final": "\uFEDE",
18096             "initial": "\uFEDF",
18097             "medial": "\uFEE0"
18098           },
18099           "meem": {
18100             "normal": ["\u0645"],
18101             "dot_above": ["\u0765"],
18102             "dot_below": ["\u0766"],
18103             "three_dots_above": ["\u08A7"],
18104             "isolated": "\uFEE1",
18105             "final": "\uFEE2",
18106             "initial": "\uFEE3",
18107             "medial": "\uFEE4"
18108           },
18109           "noon": {
18110             "normal": ["\u0646"],
18111             "dot_below": ["\u06B9"],
18112             "ring": ["\u06BC"],
18113             "three_dots_above": ["\u06BD"],
18114             "two_dots_below": ["\u0767"],
18115             "small_tah": ["\u0768"],
18116             "small_v": ["\u0769"],
18117             "isolated": "\uFEE5",
18118             "final": "\uFEE6",
18119             "initial": "\uFEE7",
18120             "medial": "\uFEE8"
18121           },
18122           "heh": {
18123             "normal": ["\u0647"],
18124             "isolated": "\uFEE9",
18125             "final": "\uFEEA",
18126             "initial": "\uFEEB",
18127             "medial": "\uFEEC"
18128           },
18129           "waw": {
18130             "normal": ["\u0648"],
18131             "hamza_above": {
18132               "normal": ["\u0624", "\u0648\u0654"],
18133               "isolated": "\uFE85",
18134               "final": "\uFE86"
18135             },
18136             "high_hamza": ["\u0676", "\u0648\u0674"],
18137             "ring": ["\u06C4"],
18138             "two_dots_above": ["\u06CA"],
18139             "dot_above": ["\u06CF"],
18140             "indic_two_above": ["\u0778"],
18141             "indic_three_above": ["\u0779"],
18142             "dot_within": ["\u08AB"],
18143             "isolated": "\uFEED",
18144             "final": "\uFEEE"
18145           },
18146           "alef_maksura": {
18147             "normal": ["\u0649"],
18148             "hamza_above": ["\u0626", "\u064A\u0654"],
18149             "initial": "\uFBE8",
18150             "medial": "\uFBE9",
18151             "isolated": "\uFEEF",
18152             "final": "\uFEF0"
18153           },
18154           "yeh": {
18155             "normal": ["\u064A"],
18156             "hamza_above": {
18157               "normal": ["\u0626", "\u0649\u0654"],
18158               "isolated": "\uFE89",
18159               "final": "\uFE8A",
18160               "initial": "\uFE8B",
18161               "medial": "\uFE8C"
18162             },
18163             "two_dots_below_hamza_above": ["\u08A8"],
18164             "high_hamza": ["\u0678", "\u064A\u0674"],
18165             "tail": ["\u06CD"],
18166             "small_v": ["\u06CE"],
18167             "three_dots_below": ["\u06D1"],
18168             "two_dots_below_dot_above": ["\u08A9"],
18169             "two_dots_below_small_noon_above": ["\u08BA"],
18170             "isolated": "\uFEF1",
18171             "final": "\uFEF2",
18172             "initial": "\uFEF3",
18173             "medial": "\uFEF4"
18174           },
18175           "tteh": {
18176             "normal": ["\u0679"],
18177             "isolated": "\uFB66",
18178             "final": "\uFB67",
18179             "initial": "\uFB68",
18180             "medial": "\uFB69"
18181           },
18182           "tteheh": {
18183             "normal": ["\u067A"],
18184             "isolated": "\uFB5E",
18185             "final": "\uFB5F",
18186             "initial": "\uFB60",
18187             "medial": "\uFB61"
18188           },
18189           "beeh": {
18190             "normal": ["\u067B"],
18191             "isolated": "\uFB52",
18192             "final": "\uFB53",
18193             "initial": "\uFB54",
18194             "medial": "\uFB55"
18195           },
18196           "peh": {
18197             "normal": ["\u067E"],
18198             "small_meem_above": ["\u08B7"],
18199             "isolated": "\uFB56",
18200             "final": "\uFB57",
18201             "initial": "\uFB58",
18202             "medial": "\uFB59"
18203           },
18204           "teheh": {
18205             "normal": ["\u067F"],
18206             "isolated": "\uFB62",
18207             "final": "\uFB63",
18208             "initial": "\uFB64",
18209             "medial": "\uFB65"
18210           },
18211           "beheh": {
18212             "normal": ["\u0680"],
18213             "isolated": "\uFB5A",
18214             "final": "\uFB5B",
18215             "initial": "\uFB5C",
18216             "medial": "\uFB5D"
18217           },
18218           "nyeh": {
18219             "normal": ["\u0683"],
18220             "isolated": "\uFB76",
18221             "final": "\uFB77",
18222             "initial": "\uFB78",
18223             "medial": "\uFB79"
18224           },
18225           "dyeh": {
18226             "normal": ["\u0684"],
18227             "isolated": "\uFB72",
18228             "final": "\uFB73",
18229             "initial": "\uFB74",
18230             "medial": "\uFB75"
18231           },
18232           "tcheh": {
18233             "normal": ["\u0686"],
18234             "dot_above": ["\u06BF"],
18235             "isolated": "\uFB7A",
18236             "final": "\uFB7B",
18237             "initial": "\uFB7C",
18238             "medial": "\uFB7D"
18239           },
18240           "tcheheh": {
18241             "normal": ["\u0687"],
18242             "isolated": "\uFB7E",
18243             "final": "\uFB7F",
18244             "initial": "\uFB80",
18245             "medial": "\uFB81"
18246           },
18247           "ddal": {
18248             "normal": ["\u0688"],
18249             "isolated": "\uFB88",
18250             "final": "\uFB89"
18251           },
18252           "dahal": {
18253             "normal": ["\u068C"],
18254             "isolated": "\uFB84",
18255             "final": "\uFB85"
18256           },
18257           "ddahal": {
18258             "normal": ["\u068D"],
18259             "isolated": "\uFB82",
18260             "final": "\uFB83"
18261           },
18262           "dul": {
18263             "normal": ["\u068F", "\u068E"],
18264             "isolated": "\uFB86",
18265             "final": "\uFB87"
18266           },
18267           "rreh": {
18268             "normal": ["\u0691"],
18269             "isolated": "\uFB8C",
18270             "final": "\uFB8D"
18271           },
18272           "jeh": {
18273             "normal": ["\u0698"],
18274             "isolated": "\uFB8A",
18275             "final": "\uFB8B"
18276           },
18277           "veh": {
18278             "normal": ["\u06A4"],
18279             "isolated": "\uFB6A",
18280             "final": "\uFB6B",
18281             "initial": "\uFB6C",
18282             "medial": "\uFB6D"
18283           },
18284           "peheh": {
18285             "normal": ["\u06A6"],
18286             "isolated": "\uFB6E",
18287             "final": "\uFB6F",
18288             "initial": "\uFB70",
18289             "medial": "\uFB71"
18290           },
18291           "keheh": {
18292             "normal": ["\u06A9"],
18293             "dot_above": ["\u0762"],
18294             "three_dots_above": ["\u0763"],
18295             "three_dots_pointing_upwards_below": ["\u0764"],
18296             "isolated": "\uFB8E",
18297             "final": "\uFB8F",
18298             "initial": "\uFB90",
18299             "medial": "\uFB91"
18300           },
18301           "ng": {
18302             "normal": ["\u06AD"],
18303             "isolated": "\uFBD3",
18304             "final": "\uFBD4",
18305             "initial": "\uFBD5",
18306             "medial": "\uFBD6"
18307           },
18308           "gaf": {
18309             "normal": ["\u06AF"],
18310             "ring": ["\u06B0"],
18311             "two_dots_below": ["\u06B2"],
18312             "three_dots_above": ["\u06B4"],
18313             "inverted_stroke": ["\u08B0"],
18314             "isolated": "\uFB92",
18315             "final": "\uFB93",
18316             "initial": "\uFB94",
18317             "medial": "\uFB95"
18318           },
18319           "ngoeh": {
18320             "normal": ["\u06B1"],
18321             "isolated": "\uFB9A",
18322             "final": "\uFB9B",
18323             "initial": "\uFB9C",
18324             "medial": "\uFB9D"
18325           },
18326           "gueh": {
18327             "normal": ["\u06B3"],
18328             "isolated": "\uFB96",
18329             "final": "\uFB97",
18330             "initial": "\uFB98",
18331             "medial": "\uFB99"
18332           },
18333           "noon ghunna": {
18334             "normal": ["\u06BA"],
18335             "isolated": "\uFB9E",
18336             "final": "\uFB9F"
18337           },
18338           "rnoon": {
18339             "normal": ["\u06BB"],
18340             "isolated": "\uFBA0",
18341             "final": "\uFBA1",
18342             "initial": "\uFBA2",
18343             "medial": "\uFBA3"
18344           },
18345           "heh doachashmee": {
18346             "normal": ["\u06BE"],
18347             "isolated": "\uFBAA",
18348             "final": "\uFBAB",
18349             "initial": "\uFBAC",
18350             "medial": "\uFBAD"
18351           },
18352           "heh goal": {
18353             "normal": ["\u06C1"],
18354             "hamza_above": ["\u06C1\u0654", "\u06C2"],
18355             "isolated": "\uFBA6",
18356             "final": "\uFBA7",
18357             "initial": "\uFBA8",
18358             "medial": "\uFBA9"
18359           },
18360           "teh marbuta goal": {
18361             "normal": ["\u06C3"]
18362           },
18363           "kirghiz oe": {
18364             "normal": ["\u06C5"],
18365             "isolated": "\uFBE0",
18366             "final": "\uFBE1"
18367           },
18368           "oe": {
18369             "normal": ["\u06C6"],
18370             "isolated": "\uFBD9",
18371             "final": "\uFBDA"
18372           },
18373           "u": {
18374             "normal": ["\u06C7"],
18375             "hamza_above": {
18376               "normal": ["\u0677", "\u06C7\u0674"],
18377               "isolated": "\uFBDD"
18378             },
18379             "isolated": "\uFBD7",
18380             "final": "\uFBD8"
18381           },
18382           "yu": {
18383             "normal": ["\u06C8"],
18384             "isolated": "\uFBDB",
18385             "final": "\uFBDC"
18386           },
18387           "kirghiz yu": {
18388             "normal": ["\u06C9"],
18389             "isolated": "\uFBE2",
18390             "final": "\uFBE3"
18391           },
18392           "ve": {
18393             "normal": ["\u06CB"],
18394             "isolated": "\uFBDE",
18395             "final": "\uFBDF"
18396           },
18397           "farsi yeh": {
18398             "normal": ["\u06CC"],
18399             "indic_two_above": ["\u0775"],
18400             "indic_three_above": ["\u0776"],
18401             "indic_four_above": ["\u0777"],
18402             "isolated": "\uFBFC",
18403             "final": "\uFBFD",
18404             "initial": "\uFBFE",
18405             "medial": "\uFBFF"
18406           },
18407           "e": {
18408             "normal": ["\u06D0"],
18409             "isolated": "\uFBE4",
18410             "final": "\uFBE5",
18411             "initial": "\uFBE6",
18412             "medial": "\uFBE7"
18413           },
18414           "yeh barree": {
18415             "normal": ["\u06D2"],
18416             "hamza_above": {
18417               "normal": ["\u06D2\u0654", "\u06D3"],
18418               "isolated": "\uFBB0",
18419               "final": "\uFBB1"
18420             },
18421             "indic_two_above": ["\u077A"],
18422             "indic_three_above": ["\u077B"],
18423             "isolated": "\uFBAE",
18424             "final": "\uFBAF"
18425           },
18426           "ae": {
18427             "normal": ["\u06D5"],
18428             "isolated": "\u06D5",
18429             "final": "\uFEEA",
18430             "yeh_above": {
18431               "normal": ["\u06C0", "\u06D5\u0654"],
18432               "isolated": "\uFBA4",
18433               "final": "\uFBA5"
18434             }
18435           },
18436           "rohingya yeh": {
18437             "normal": ["\u08AC"]
18438           },
18439           "low alef": {
18440             "normal": ["\u08AD"]
18441           },
18442           "straight waw": {
18443             "normal": ["\u08B1"]
18444           },
18445           "african feh": {
18446             "normal": ["\u08BB"]
18447           },
18448           "african qaf": {
18449             "normal": ["\u08BC"]
18450           },
18451           "african noon": {
18452             "normal": ["\u08BD"]
18453           }
18454         };
18455         var _default$3 = arabicReference;
18456         var unicodeArabic = /*#__PURE__*/Object.defineProperty({
18457           "default": _default$3
18458         }, '__esModule', {
18459           value: true
18460         });
18461
18462         var ligatureReference = {
18463           "\u0626\u0627": {
18464             "isolated": "\uFBEA",
18465             "final": "\uFBEB"
18466           },
18467           "\u0626\u06D5": {
18468             "isolated": "\uFBEC",
18469             "final": "\uFBED"
18470           },
18471           "\u0626\u0648": {
18472             "isolated": "\uFBEE",
18473             "final": "\uFBEF"
18474           },
18475           "\u0626\u06C7": {
18476             "isolated": "\uFBF0",
18477             "final": "\uFBF1"
18478           },
18479           "\u0626\u06C6": {
18480             "isolated": "\uFBF2",
18481             "final": "\uFBF3"
18482           },
18483           "\u0626\u06C8": {
18484             "isolated": "\uFBF4",
18485             "final": "\uFBF5"
18486           },
18487           "\u0626\u06D0": {
18488             "isolated": "\uFBF6",
18489             "final": "\uFBF7",
18490             "initial": "\uFBF8"
18491           },
18492           "\u0626\u0649": {
18493             "uighur_kirghiz": {
18494               "isolated": "\uFBF9",
18495               "final": "\uFBFA",
18496               "initial": "\uFBFB"
18497             },
18498             "isolated": "\uFC03",
18499             "final": "\uFC68"
18500           },
18501           "\u0626\u062C": {
18502             "isolated": "\uFC00",
18503             "initial": "\uFC97"
18504           },
18505           "\u0626\u062D": {
18506             "isolated": "\uFC01",
18507             "initial": "\uFC98"
18508           },
18509           "\u0626\u0645": {
18510             "isolated": "\uFC02",
18511             "final": "\uFC66",
18512             "initial": "\uFC9A",
18513             "medial": "\uFCDF"
18514           },
18515           "\u0626\u064A": {
18516             "isolated": "\uFC04",
18517             "final": "\uFC69"
18518           },
18519           "\u0628\u062C": {
18520             "isolated": "\uFC05",
18521             "initial": "\uFC9C"
18522           },
18523           "\u0628\u062D": {
18524             "isolated": "\uFC06",
18525             "initial": "\uFC9D"
18526           },
18527           "\u0628\u062E": {
18528             "isolated": "\uFC07",
18529             "initial": "\uFC9E"
18530           },
18531           "\u0628\u0645": {
18532             "isolated": "\uFC08",
18533             "final": "\uFC6C",
18534             "initial": "\uFC9F",
18535             "medial": "\uFCE1"
18536           },
18537           "\u0628\u0649": {
18538             "isolated": "\uFC09",
18539             "final": "\uFC6E"
18540           },
18541           "\u0628\u064A": {
18542             "isolated": "\uFC0A",
18543             "final": "\uFC6F"
18544           },
18545           "\u062A\u062C": {
18546             "isolated": "\uFC0B",
18547             "initial": "\uFCA1"
18548           },
18549           "\u062A\u062D": {
18550             "isolated": "\uFC0C",
18551             "initial": "\uFCA2"
18552           },
18553           "\u062A\u062E": {
18554             "isolated": "\uFC0D",
18555             "initial": "\uFCA3"
18556           },
18557           "\u062A\u0645": {
18558             "isolated": "\uFC0E",
18559             "final": "\uFC72",
18560             "initial": "\uFCA4",
18561             "medial": "\uFCE3"
18562           },
18563           "\u062A\u0649": {
18564             "isolated": "\uFC0F",
18565             "final": "\uFC74"
18566           },
18567           "\u062A\u064A": {
18568             "isolated": "\uFC10",
18569             "final": "\uFC75"
18570           },
18571           "\u062B\u062C": {
18572             "isolated": "\uFC11"
18573           },
18574           "\u062B\u0645": {
18575             "isolated": "\uFC12",
18576             "final": "\uFC78",
18577             "initial": "\uFCA6",
18578             "medial": "\uFCE5"
18579           },
18580           "\u062B\u0649": {
18581             "isolated": "\uFC13",
18582             "final": "\uFC7A"
18583           },
18584           "\u062B\u0648": {
18585             "isolated": "\uFC14"
18586           },
18587           "\u062C\u062D": {
18588             "isolated": "\uFC15",
18589             "initial": "\uFCA7"
18590           },
18591           "\u062C\u0645": {
18592             "isolated": "\uFC16",
18593             "initial": "\uFCA8"
18594           },
18595           "\u062D\u062C": {
18596             "isolated": "\uFC17",
18597             "initial": "\uFCA9"
18598           },
18599           "\u062D\u0645": {
18600             "isolated": "\uFC18",
18601             "initial": "\uFCAA"
18602           },
18603           "\u062E\u062C": {
18604             "isolated": "\uFC19",
18605             "initial": "\uFCAB"
18606           },
18607           "\u062E\u062D": {
18608             "isolated": "\uFC1A"
18609           },
18610           "\u062E\u0645": {
18611             "isolated": "\uFC1B",
18612             "initial": "\uFCAC"
18613           },
18614           "\u0633\u062C": {
18615             "isolated": "\uFC1C",
18616             "initial": "\uFCAD",
18617             "medial": "\uFD34"
18618           },
18619           "\u0633\u062D": {
18620             "isolated": "\uFC1D",
18621             "initial": "\uFCAE",
18622             "medial": "\uFD35"
18623           },
18624           "\u0633\u062E": {
18625             "isolated": "\uFC1E",
18626             "initial": "\uFCAF",
18627             "medial": "\uFD36"
18628           },
18629           "\u0633\u0645": {
18630             "isolated": "\uFC1F",
18631             "initial": "\uFCB0",
18632             "medial": "\uFCE7"
18633           },
18634           "\u0635\u062D": {
18635             "isolated": "\uFC20",
18636             "initial": "\uFCB1"
18637           },
18638           "\u0635\u0645": {
18639             "isolated": "\uFC21",
18640             "initial": "\uFCB3"
18641           },
18642           "\u0636\u062C": {
18643             "isolated": "\uFC22",
18644             "initial": "\uFCB4"
18645           },
18646           "\u0636\u062D": {
18647             "isolated": "\uFC23",
18648             "initial": "\uFCB5"
18649           },
18650           "\u0636\u062E": {
18651             "isolated": "\uFC24",
18652             "initial": "\uFCB6"
18653           },
18654           "\u0636\u0645": {
18655             "isolated": "\uFC25",
18656             "initial": "\uFCB7"
18657           },
18658           "\u0637\u062D": {
18659             "isolated": "\uFC26",
18660             "initial": "\uFCB8"
18661           },
18662           "\u0637\u0645": {
18663             "isolated": "\uFC27",
18664             "initial": "\uFD33",
18665             "medial": "\uFD3A"
18666           },
18667           "\u0638\u0645": {
18668             "isolated": "\uFC28",
18669             "initial": "\uFCB9",
18670             "medial": "\uFD3B"
18671           },
18672           "\u0639\u062C": {
18673             "isolated": "\uFC29",
18674             "initial": "\uFCBA"
18675           },
18676           "\u0639\u0645": {
18677             "isolated": "\uFC2A",
18678             "initial": "\uFCBB"
18679           },
18680           "\u063A\u062C": {
18681             "isolated": "\uFC2B",
18682             "initial": "\uFCBC"
18683           },
18684           "\u063A\u0645": {
18685             "isolated": "\uFC2C",
18686             "initial": "\uFCBD"
18687           },
18688           "\u0641\u062C": {
18689             "isolated": "\uFC2D",
18690             "initial": "\uFCBE"
18691           },
18692           "\u0641\u062D": {
18693             "isolated": "\uFC2E",
18694             "initial": "\uFCBF"
18695           },
18696           "\u0641\u062E": {
18697             "isolated": "\uFC2F",
18698             "initial": "\uFCC0"
18699           },
18700           "\u0641\u0645": {
18701             "isolated": "\uFC30",
18702             "initial": "\uFCC1"
18703           },
18704           "\u0641\u0649": {
18705             "isolated": "\uFC31",
18706             "final": "\uFC7C"
18707           },
18708           "\u0641\u064A": {
18709             "isolated": "\uFC32",
18710             "final": "\uFC7D"
18711           },
18712           "\u0642\u062D": {
18713             "isolated": "\uFC33",
18714             "initial": "\uFCC2"
18715           },
18716           "\u0642\u0645": {
18717             "isolated": "\uFC34",
18718             "initial": "\uFCC3"
18719           },
18720           "\u0642\u0649": {
18721             "isolated": "\uFC35",
18722             "final": "\uFC7E"
18723           },
18724           "\u0642\u064A": {
18725             "isolated": "\uFC36",
18726             "final": "\uFC7F"
18727           },
18728           "\u0643\u0627": {
18729             "isolated": "\uFC37",
18730             "final": "\uFC80"
18731           },
18732           "\u0643\u062C": {
18733             "isolated": "\uFC38",
18734             "initial": "\uFCC4"
18735           },
18736           "\u0643\u062D": {
18737             "isolated": "\uFC39",
18738             "initial": "\uFCC5"
18739           },
18740           "\u0643\u062E": {
18741             "isolated": "\uFC3A",
18742             "initial": "\uFCC6"
18743           },
18744           "\u0643\u0644": {
18745             "isolated": "\uFC3B",
18746             "final": "\uFC81",
18747             "initial": "\uFCC7",
18748             "medial": "\uFCEB"
18749           },
18750           "\u0643\u0645": {
18751             "isolated": "\uFC3C",
18752             "final": "\uFC82",
18753             "initial": "\uFCC8",
18754             "medial": "\uFCEC"
18755           },
18756           "\u0643\u0649": {
18757             "isolated": "\uFC3D",
18758             "final": "\uFC83"
18759           },
18760           "\u0643\u064A": {
18761             "isolated": "\uFC3E",
18762             "final": "\uFC84"
18763           },
18764           "\u0644\u062C": {
18765             "isolated": "\uFC3F",
18766             "initial": "\uFCC9"
18767           },
18768           "\u0644\u062D": {
18769             "isolated": "\uFC40",
18770             "initial": "\uFCCA"
18771           },
18772           "\u0644\u062E": {
18773             "isolated": "\uFC41",
18774             "initial": "\uFCCB"
18775           },
18776           "\u0644\u0645": {
18777             "isolated": "\uFC42",
18778             "final": "\uFC85",
18779             "initial": "\uFCCC",
18780             "medial": "\uFCED"
18781           },
18782           "\u0644\u0649": {
18783             "isolated": "\uFC43",
18784             "final": "\uFC86"
18785           },
18786           "\u0644\u064A": {
18787             "isolated": "\uFC44",
18788             "final": "\uFC87"
18789           },
18790           "\u0645\u062C": {
18791             "isolated": "\uFC45",
18792             "initial": "\uFCCE"
18793           },
18794           "\u0645\u062D": {
18795             "isolated": "\uFC46",
18796             "initial": "\uFCCF"
18797           },
18798           "\u0645\u062E": {
18799             "isolated": "\uFC47",
18800             "initial": "\uFCD0"
18801           },
18802           "\u0645\u0645": {
18803             "isolated": "\uFC48",
18804             "final": "\uFC89",
18805             "initial": "\uFCD1"
18806           },
18807           "\u0645\u0649": {
18808             "isolated": "\uFC49"
18809           },
18810           "\u0645\u064A": {
18811             "isolated": "\uFC4A"
18812           },
18813           "\u0646\u062C": {
18814             "isolated": "\uFC4B",
18815             "initial": "\uFCD2"
18816           },
18817           "\u0646\u062D": {
18818             "isolated": "\uFC4C",
18819             "initial": "\uFCD3"
18820           },
18821           "\u0646\u062E": {
18822             "isolated": "\uFC4D",
18823             "initial": "\uFCD4"
18824           },
18825           "\u0646\u0645": {
18826             "isolated": "\uFC4E",
18827             "final": "\uFC8C",
18828             "initial": "\uFCD5",
18829             "medial": "\uFCEE"
18830           },
18831           "\u0646\u0649": {
18832             "isolated": "\uFC4F",
18833             "final": "\uFC8E"
18834           },
18835           "\u0646\u064A": {
18836             "isolated": "\uFC50",
18837             "final": "\uFC8F"
18838           },
18839           "\u0647\u062C": {
18840             "isolated": "\uFC51",
18841             "initial": "\uFCD7"
18842           },
18843           "\u0647\u0645": {
18844             "isolated": "\uFC52",
18845             "initial": "\uFCD8"
18846           },
18847           "\u0647\u0649": {
18848             "isolated": "\uFC53"
18849           },
18850           "\u0647\u064A": {
18851             "isolated": "\uFC54"
18852           },
18853           "\u064A\u062C": {
18854             "isolated": "\uFC55",
18855             "initial": "\uFCDA"
18856           },
18857           "\u064A\u062D": {
18858             "isolated": "\uFC56",
18859             "initial": "\uFCDB"
18860           },
18861           "\u064A\u062E": {
18862             "isolated": "\uFC57",
18863             "initial": "\uFCDC"
18864           },
18865           "\u064A\u0645": {
18866             "isolated": "\uFC58",
18867             "final": "\uFC93",
18868             "initial": "\uFCDD",
18869             "medial": "\uFCF0"
18870           },
18871           "\u064A\u0649": {
18872             "isolated": "\uFC59",
18873             "final": "\uFC95"
18874           },
18875           "\u064A\u064A": {
18876             "isolated": "\uFC5A",
18877             "final": "\uFC96"
18878           },
18879           "\u0630\u0670": {
18880             "isolated": "\uFC5B"
18881           },
18882           "\u0631\u0670": {
18883             "isolated": "\uFC5C"
18884           },
18885           "\u0649\u0670": {
18886             "isolated": "\uFC5D",
18887             "final": "\uFC90"
18888           },
18889           "\u064C\u0651": {
18890             "isolated": "\uFC5E"
18891           },
18892           "\u064D\u0651": {
18893             "isolated": "\uFC5F"
18894           },
18895           "\u064E\u0651": {
18896             "isolated": "\uFC60"
18897           },
18898           "\u064F\u0651": {
18899             "isolated": "\uFC61"
18900           },
18901           "\u0650\u0651": {
18902             "isolated": "\uFC62"
18903           },
18904           "\u0651\u0670": {
18905             "isolated": "\uFC63"
18906           },
18907           "\u0626\u0631": {
18908             "final": "\uFC64"
18909           },
18910           "\u0626\u0632": {
18911             "final": "\uFC65"
18912           },
18913           "\u0626\u0646": {
18914             "final": "\uFC67"
18915           },
18916           "\u0628\u0631": {
18917             "final": "\uFC6A"
18918           },
18919           "\u0628\u0632": {
18920             "final": "\uFC6B"
18921           },
18922           "\u0628\u0646": {
18923             "final": "\uFC6D"
18924           },
18925           "\u062A\u0631": {
18926             "final": "\uFC70"
18927           },
18928           "\u062A\u0632": {
18929             "final": "\uFC71"
18930           },
18931           "\u062A\u0646": {
18932             "final": "\uFC73"
18933           },
18934           "\u062B\u0631": {
18935             "final": "\uFC76"
18936           },
18937           "\u062B\u0632": {
18938             "final": "\uFC77"
18939           },
18940           "\u062B\u0646": {
18941             "final": "\uFC79"
18942           },
18943           "\u062B\u064A": {
18944             "final": "\uFC7B"
18945           },
18946           "\u0645\u0627": {
18947             "final": "\uFC88"
18948           },
18949           "\u0646\u0631": {
18950             "final": "\uFC8A"
18951           },
18952           "\u0646\u0632": {
18953             "final": "\uFC8B"
18954           },
18955           "\u0646\u0646": {
18956             "final": "\uFC8D"
18957           },
18958           "\u064A\u0631": {
18959             "final": "\uFC91"
18960           },
18961           "\u064A\u0632": {
18962             "final": "\uFC92"
18963           },
18964           "\u064A\u0646": {
18965             "final": "\uFC94"
18966           },
18967           "\u0626\u062E": {
18968             "initial": "\uFC99"
18969           },
18970           "\u0626\u0647": {
18971             "initial": "\uFC9B",
18972             "medial": "\uFCE0"
18973           },
18974           "\u0628\u0647": {
18975             "initial": "\uFCA0",
18976             "medial": "\uFCE2"
18977           },
18978           "\u062A\u0647": {
18979             "initial": "\uFCA5",
18980             "medial": "\uFCE4"
18981           },
18982           "\u0635\u062E": {
18983             "initial": "\uFCB2"
18984           },
18985           "\u0644\u0647": {
18986             "initial": "\uFCCD"
18987           },
18988           "\u0646\u0647": {
18989             "initial": "\uFCD6",
18990             "medial": "\uFCEF"
18991           },
18992           "\u0647\u0670": {
18993             "initial": "\uFCD9"
18994           },
18995           "\u064A\u0647": {
18996             "initial": "\uFCDE",
18997             "medial": "\uFCF1"
18998           },
18999           "\u062B\u0647": {
19000             "medial": "\uFCE6"
19001           },
19002           "\u0633\u0647": {
19003             "medial": "\uFCE8",
19004             "initial": "\uFD31"
19005           },
19006           "\u0634\u0645": {
19007             "medial": "\uFCE9",
19008             "isolated": "\uFD0C",
19009             "final": "\uFD28",
19010             "initial": "\uFD30"
19011           },
19012           "\u0634\u0647": {
19013             "medial": "\uFCEA",
19014             "initial": "\uFD32"
19015           },
19016           "\u0640\u064E\u0651": {
19017             "medial": "\uFCF2"
19018           },
19019           "\u0640\u064F\u0651": {
19020             "medial": "\uFCF3"
19021           },
19022           "\u0640\u0650\u0651": {
19023             "medial": "\uFCF4"
19024           },
19025           "\u0637\u0649": {
19026             "isolated": "\uFCF5",
19027             "final": "\uFD11"
19028           },
19029           "\u0637\u064A": {
19030             "isolated": "\uFCF6",
19031             "final": "\uFD12"
19032           },
19033           "\u0639\u0649": {
19034             "isolated": "\uFCF7",
19035             "final": "\uFD13"
19036           },
19037           "\u0639\u064A": {
19038             "isolated": "\uFCF8",
19039             "final": "\uFD14"
19040           },
19041           "\u063A\u0649": {
19042             "isolated": "\uFCF9",
19043             "final": "\uFD15"
19044           },
19045           "\u063A\u064A": {
19046             "isolated": "\uFCFA",
19047             "final": "\uFD16"
19048           },
19049           "\u0633\u0649": {
19050             "isolated": "\uFCFB"
19051           },
19052           "\u0633\u064A": {
19053             "isolated": "\uFCFC",
19054             "final": "\uFD18"
19055           },
19056           "\u0634\u0649": {
19057             "isolated": "\uFCFD",
19058             "final": "\uFD19"
19059           },
19060           "\u0634\u064A": {
19061             "isolated": "\uFCFE",
19062             "final": "\uFD1A"
19063           },
19064           "\u062D\u0649": {
19065             "isolated": "\uFCFF",
19066             "final": "\uFD1B"
19067           },
19068           "\u062D\u064A": {
19069             "isolated": "\uFD00",
19070             "final": "\uFD1C"
19071           },
19072           "\u062C\u0649": {
19073             "isolated": "\uFD01",
19074             "final": "\uFD1D"
19075           },
19076           "\u062C\u064A": {
19077             "isolated": "\uFD02",
19078             "final": "\uFD1E"
19079           },
19080           "\u062E\u0649": {
19081             "isolated": "\uFD03",
19082             "final": "\uFD1F"
19083           },
19084           "\u062E\u064A": {
19085             "isolated": "\uFD04",
19086             "final": "\uFD20"
19087           },
19088           "\u0635\u0649": {
19089             "isolated": "\uFD05",
19090             "final": "\uFD21"
19091           },
19092           "\u0635\u064A": {
19093             "isolated": "\uFD06",
19094             "final": "\uFD22"
19095           },
19096           "\u0636\u0649": {
19097             "isolated": "\uFD07",
19098             "final": "\uFD23"
19099           },
19100           "\u0636\u064A": {
19101             "isolated": "\uFD08",
19102             "final": "\uFD24"
19103           },
19104           "\u0634\u062C": {
19105             "isolated": "\uFD09",
19106             "final": "\uFD25",
19107             "initial": "\uFD2D",
19108             "medial": "\uFD37"
19109           },
19110           "\u0634\u062D": {
19111             "isolated": "\uFD0A",
19112             "final": "\uFD26",
19113             "initial": "\uFD2E",
19114             "medial": "\uFD38"
19115           },
19116           "\u0634\u062E": {
19117             "isolated": "\uFD0B",
19118             "final": "\uFD27",
19119             "initial": "\uFD2F",
19120             "medial": "\uFD39"
19121           },
19122           "\u0634\u0631": {
19123             "isolated": "\uFD0D",
19124             "final": "\uFD29"
19125           },
19126           "\u0633\u0631": {
19127             "isolated": "\uFD0E",
19128             "final": "\uFD2A"
19129           },
19130           "\u0635\u0631": {
19131             "isolated": "\uFD0F",
19132             "final": "\uFD2B"
19133           },
19134           "\u0636\u0631": {
19135             "isolated": "\uFD10",
19136             "final": "\uFD2C"
19137           },
19138           "\u0633\u0639": {
19139             "final": "\uFD17"
19140           },
19141           "\u062A\u062C\u0645": {
19142             "initial": "\uFD50"
19143           },
19144           "\u062A\u062D\u062C": {
19145             "final": "\uFD51",
19146             "initial": "\uFD52"
19147           },
19148           "\u062A\u062D\u0645": {
19149             "initial": "\uFD53"
19150           },
19151           "\u062A\u062E\u0645": {
19152             "initial": "\uFD54"
19153           },
19154           "\u062A\u0645\u062C": {
19155             "initial": "\uFD55"
19156           },
19157           "\u062A\u0645\u062D": {
19158             "initial": "\uFD56"
19159           },
19160           "\u062A\u0645\u062E": {
19161             "initial": "\uFD57"
19162           },
19163           "\u062C\u0645\u062D": {
19164             "final": "\uFD58",
19165             "initial": "\uFD59"
19166           },
19167           "\u062D\u0645\u064A": {
19168             "final": "\uFD5A"
19169           },
19170           "\u062D\u0645\u0649": {
19171             "final": "\uFD5B"
19172           },
19173           "\u0633\u062D\u062C": {
19174             "initial": "\uFD5C"
19175           },
19176           "\u0633\u062C\u062D": {
19177             "initial": "\uFD5D"
19178           },
19179           "\u0633\u062C\u0649": {
19180             "final": "\uFD5E"
19181           },
19182           "\u0633\u0645\u062D": {
19183             "final": "\uFD5F",
19184             "initial": "\uFD60"
19185           },
19186           "\u0633\u0645\u062C": {
19187             "initial": "\uFD61"
19188           },
19189           "\u0633\u0645\u0645": {
19190             "final": "\uFD62",
19191             "initial": "\uFD63"
19192           },
19193           "\u0635\u062D\u062D": {
19194             "final": "\uFD64",
19195             "initial": "\uFD65"
19196           },
19197           "\u0635\u0645\u0645": {
19198             "final": "\uFD66",
19199             "initial": "\uFDC5"
19200           },
19201           "\u0634\u062D\u0645": {
19202             "final": "\uFD67",
19203             "initial": "\uFD68"
19204           },
19205           "\u0634\u062C\u064A": {
19206             "final": "\uFD69"
19207           },
19208           "\u0634\u0645\u062E": {
19209             "final": "\uFD6A",
19210             "initial": "\uFD6B"
19211           },
19212           "\u0634\u0645\u0645": {
19213             "final": "\uFD6C",
19214             "initial": "\uFD6D"
19215           },
19216           "\u0636\u062D\u0649": {
19217             "final": "\uFD6E"
19218           },
19219           "\u0636\u062E\u0645": {
19220             "final": "\uFD6F",
19221             "initial": "\uFD70"
19222           },
19223           "\u0636\u0645\u062D": {
19224             "final": "\uFD71"
19225           },
19226           "\u0637\u0645\u062D": {
19227             "initial": "\uFD72"
19228           },
19229           "\u0637\u0645\u0645": {
19230             "initial": "\uFD73"
19231           },
19232           "\u0637\u0645\u064A": {
19233             "final": "\uFD74"
19234           },
19235           "\u0639\u062C\u0645": {
19236             "final": "\uFD75",
19237             "initial": "\uFDC4"
19238           },
19239           "\u0639\u0645\u0645": {
19240             "final": "\uFD76",
19241             "initial": "\uFD77"
19242           },
19243           "\u0639\u0645\u0649": {
19244             "final": "\uFD78"
19245           },
19246           "\u063A\u0645\u0645": {
19247             "final": "\uFD79"
19248           },
19249           "\u063A\u0645\u064A": {
19250             "final": "\uFD7A"
19251           },
19252           "\u063A\u0645\u0649": {
19253             "final": "\uFD7B"
19254           },
19255           "\u0641\u062E\u0645": {
19256             "final": "\uFD7C",
19257             "initial": "\uFD7D"
19258           },
19259           "\u0642\u0645\u062D": {
19260             "final": "\uFD7E",
19261             "initial": "\uFDB4"
19262           },
19263           "\u0642\u0645\u0645": {
19264             "final": "\uFD7F"
19265           },
19266           "\u0644\u062D\u0645": {
19267             "final": "\uFD80",
19268             "initial": "\uFDB5"
19269           },
19270           "\u0644\u062D\u064A": {
19271             "final": "\uFD81"
19272           },
19273           "\u0644\u062D\u0649": {
19274             "final": "\uFD82"
19275           },
19276           "\u0644\u062C\u062C": {
19277             "initial": "\uFD83",
19278             "final": "\uFD84"
19279           },
19280           "\u0644\u062E\u0645": {
19281             "final": "\uFD85",
19282             "initial": "\uFD86"
19283           },
19284           "\u0644\u0645\u062D": {
19285             "final": "\uFD87",
19286             "initial": "\uFD88"
19287           },
19288           "\u0645\u062D\u062C": {
19289             "initial": "\uFD89"
19290           },
19291           "\u0645\u062D\u0645": {
19292             "initial": "\uFD8A"
19293           },
19294           "\u0645\u062D\u064A": {
19295             "final": "\uFD8B"
19296           },
19297           "\u0645\u062C\u062D": {
19298             "initial": "\uFD8C"
19299           },
19300           "\u0645\u062C\u0645": {
19301             "initial": "\uFD8D"
19302           },
19303           "\u0645\u062E\u062C": {
19304             "initial": "\uFD8E"
19305           },
19306           "\u0645\u062E\u0645": {
19307             "initial": "\uFD8F"
19308           },
19309           "\u0645\u062C\u062E": {
19310             "initial": "\uFD92"
19311           },
19312           "\u0647\u0645\u062C": {
19313             "initial": "\uFD93"
19314           },
19315           "\u0647\u0645\u0645": {
19316             "initial": "\uFD94"
19317           },
19318           "\u0646\u062D\u0645": {
19319             "initial": "\uFD95"
19320           },
19321           "\u0646\u062D\u0649": {
19322             "final": "\uFD96"
19323           },
19324           "\u0646\u062C\u0645": {
19325             "final": "\uFD97",
19326             "initial": "\uFD98"
19327           },
19328           "\u0646\u062C\u0649": {
19329             "final": "\uFD99"
19330           },
19331           "\u0646\u0645\u064A": {
19332             "final": "\uFD9A"
19333           },
19334           "\u0646\u0645\u0649": {
19335             "final": "\uFD9B"
19336           },
19337           "\u064A\u0645\u0645": {
19338             "final": "\uFD9C",
19339             "initial": "\uFD9D"
19340           },
19341           "\u0628\u062E\u064A": {
19342             "final": "\uFD9E"
19343           },
19344           "\u062A\u062C\u064A": {
19345             "final": "\uFD9F"
19346           },
19347           "\u062A\u062C\u0649": {
19348             "final": "\uFDA0"
19349           },
19350           "\u062A\u062E\u064A": {
19351             "final": "\uFDA1"
19352           },
19353           "\u062A\u062E\u0649": {
19354             "final": "\uFDA2"
19355           },
19356           "\u062A\u0645\u064A": {
19357             "final": "\uFDA3"
19358           },
19359           "\u062A\u0645\u0649": {
19360             "final": "\uFDA4"
19361           },
19362           "\u062C\u0645\u064A": {
19363             "final": "\uFDA5"
19364           },
19365           "\u062C\u062D\u0649": {
19366             "final": "\uFDA6"
19367           },
19368           "\u062C\u0645\u0649": {
19369             "final": "\uFDA7"
19370           },
19371           "\u0633\u062E\u0649": {
19372             "final": "\uFDA8"
19373           },
19374           "\u0635\u062D\u064A": {
19375             "final": "\uFDA9"
19376           },
19377           "\u0634\u062D\u064A": {
19378             "final": "\uFDAA"
19379           },
19380           "\u0636\u062D\u064A": {
19381             "final": "\uFDAB"
19382           },
19383           "\u0644\u062C\u064A": {
19384             "final": "\uFDAC"
19385           },
19386           "\u0644\u0645\u064A": {
19387             "final": "\uFDAD"
19388           },
19389           "\u064A\u062D\u064A": {
19390             "final": "\uFDAE"
19391           },
19392           "\u064A\u062C\u064A": {
19393             "final": "\uFDAF"
19394           },
19395           "\u064A\u0645\u064A": {
19396             "final": "\uFDB0"
19397           },
19398           "\u0645\u0645\u064A": {
19399             "final": "\uFDB1"
19400           },
19401           "\u0642\u0645\u064A": {
19402             "final": "\uFDB2"
19403           },
19404           "\u0646\u062D\u064A": {
19405             "final": "\uFDB3"
19406           },
19407           "\u0639\u0645\u064A": {
19408             "final": "\uFDB6"
19409           },
19410           "\u0643\u0645\u064A": {
19411             "final": "\uFDB7"
19412           },
19413           "\u0646\u062C\u062D": {
19414             "initial": "\uFDB8",
19415             "final": "\uFDBD"
19416           },
19417           "\u0645\u062E\u064A": {
19418             "final": "\uFDB9"
19419           },
19420           "\u0644\u062C\u0645": {
19421             "initial": "\uFDBA",
19422             "final": "\uFDBC"
19423           },
19424           "\u0643\u0645\u0645": {
19425             "final": "\uFDBB",
19426             "initial": "\uFDC3"
19427           },
19428           "\u062C\u062D\u064A": {
19429             "final": "\uFDBE"
19430           },
19431           "\u062D\u062C\u064A": {
19432             "final": "\uFDBF"
19433           },
19434           "\u0645\u062C\u064A": {
19435             "final": "\uFDC0"
19436           },
19437           "\u0641\u0645\u064A": {
19438             "final": "\uFDC1"
19439           },
19440           "\u0628\u062D\u064A": {
19441             "final": "\uFDC2"
19442           },
19443           "\u0633\u062E\u064A": {
19444             "final": "\uFDC6"
19445           },
19446           "\u0646\u062C\u064A": {
19447             "final": "\uFDC7"
19448           },
19449           "\u0644\u0622": {
19450             "isolated": "\uFEF5",
19451             "final": "\uFEF6"
19452           },
19453           "\u0644\u0623": {
19454             "isolated": "\uFEF7",
19455             "final": "\uFEF8"
19456           },
19457           "\u0644\u0625": {
19458             "isolated": "\uFEF9",
19459             "final": "\uFEFA"
19460           },
19461           "\u0644\u0627": {
19462             "isolated": "\uFEFB",
19463             "final": "\uFEFC"
19464           },
19465           "words": {
19466             "\u0635\u0644\u06D2": "\uFDF0",
19467             "\u0642\u0644\u06D2": "\uFDF1",
19468             "\u0627\u0644\u0644\u0647": "\uFDF2",
19469             "\u0627\u0643\u0628\u0631": "\uFDF3",
19470             "\u0645\u062D\u0645\u062F": "\uFDF4",
19471             "\u0635\u0644\u0639\u0645": "\uFDF5",
19472             "\u0631\u0633\u0648\u0644": "\uFDF6",
19473             "\u0639\u0644\u064A\u0647": "\uFDF7",
19474             "\u0648\u0633\u0644\u0645": "\uFDF8",
19475             "\u0635\u0644\u0649": "\uFDF9",
19476             "\u0635\u0644\u0649\u0627\u0644\u0644\u0647\u0639\u0644\u064A\u0647\u0648\u0633\u0644\u0645": "\uFDFA",
19477             "\u062C\u0644\u062C\u0644\u0627\u0644\u0647": "\uFDFB",
19478             "\u0631\u06CC\u0627\u0644": "\uFDFC"
19479           }
19480         };
19481         var _default$2 = ligatureReference;
19482         var unicodeLigatures = /*#__PURE__*/Object.defineProperty({
19483           "default": _default$2
19484         }, '__esModule', {
19485           value: true
19486         });
19487
19488         var reference = createCommonjsModule(function (module, exports) {
19489
19490           Object.defineProperty(exports, "__esModule", {
19491             value: true
19492           });
19493           var letterList = Object.keys(unicodeArabic["default"]);
19494           exports.letterList = letterList;
19495           var ligatureList = Object.keys(unicodeLigatures["default"]);
19496           exports.ligatureList = ligatureList;
19497           var ligatureWordList = Object.keys(unicodeLigatures["default"].words);
19498           exports.ligatureWordList = ligatureWordList;
19499           var lams = "\u0644\u06B5\u06B6\u06B7\u06B8";
19500           exports.lams = lams;
19501           var alefs = "\u0627\u0622\u0623\u0625\u0671\u0672\u0673\u0675\u0773\u0774";
19502           exports.alefs = alefs; // for (var l = 1; l < lams.length; l++) {
19503           //   console.log('-');
19504           //   for (var a = 0; a < alefs.length; a++) {
19505           //     console.log(a + ': ' + lams[l] + alefs[a]);
19506           //   }
19507           // }
19508
19509           var tashkeel = "\u0605\u0640\u0670\u0674\u06DF\u06E7\u06E8";
19510           exports.tashkeel = tashkeel;
19511
19512           function addToTashkeel(start, finish) {
19513             for (var i = start; i <= finish; i++) {
19514               exports.tashkeel = tashkeel += String.fromCharCode(i);
19515             }
19516           }
19517
19518           addToTashkeel(0x0610, 0x061A);
19519           addToTashkeel(0x064B, 0x065F);
19520           addToTashkeel(0x06D6, 0x06DC);
19521           addToTashkeel(0x06E0, 0x06E4);
19522           addToTashkeel(0x06EA, 0x06ED);
19523           addToTashkeel(0x08D3, 0x08E1);
19524           addToTashkeel(0x08E3, 0x08FF);
19525           addToTashkeel(0xFE70, 0xFE7F);
19526           var lineBreakers = "\u0627\u0629\u0648\u06C0\u06CF\u06FD\u06FE\u076B\u076C\u0771\u0773\u0774\u0778\u0779\u08E2\u08B1\u08B2\u08B9";
19527           exports.lineBreakers = lineBreakers;
19528
19529           function addToLineBreakers(start, finish) {
19530             for (var i = start; i <= finish; i++) {
19531               exports.lineBreakers = lineBreakers += String.fromCharCode(i);
19532             }
19533           }
19534
19535           addToLineBreakers(0x0600, 0x061F); // it's OK to include tashkeel in this range as it is ignored
19536
19537           addToLineBreakers(0x0621, 0x0625);
19538           addToLineBreakers(0x062F, 0x0632);
19539           addToLineBreakers(0x0660, 0x066D); // numerals, math
19540
19541           addToLineBreakers(0x0671, 0x0677);
19542           addToLineBreakers(0x0688, 0x0699);
19543           addToLineBreakers(0x06C3, 0x06CB);
19544           addToLineBreakers(0x06D2, 0x06F9);
19545           addToLineBreakers(0x0759, 0x075B);
19546           addToLineBreakers(0x08AA, 0x08AE);
19547           addToLineBreakers(0xFB50, 0xFDFD); // presentation forms look like they could connect, but never do
19548           // Presentation Forms A includes diacritics but they are meant to stand alone
19549
19550           addToLineBreakers(0xFE80, 0xFEFC); // presentation forms look like they could connect, but never do
19551           // numerals, math
19552
19553           addToLineBreakers(0x10E60, 0x10E7F);
19554           addToLineBreakers(0x1EC70, 0x1ECBF);
19555           addToLineBreakers(0x1EE00, 0x1EEFF);
19556         });
19557
19558         function GlyphSplitter(word) {
19559           var letters = [];
19560           var lastLetter = '';
19561           word.split('').forEach(function (letter) {
19562             if (isArabic_1.isArabic(letter)) {
19563               if (reference.tashkeel.indexOf(letter) > -1) {
19564                 letters[letters.length - 1] += letter;
19565               } else if (lastLetter.length && (reference.lams.indexOf(lastLetter) === 0 && reference.alefs.indexOf(letter) > -1 || reference.lams.indexOf(lastLetter) > 0 && reference.alefs.indexOf(letter) === 0)) {
19566                 // valid LA forms
19567                 letters[letters.length - 1] += letter;
19568               } else {
19569                 letters.push(letter);
19570               }
19571             } else {
19572               letters.push(letter);
19573             }
19574
19575             if (reference.tashkeel.indexOf(letter) === -1) {
19576               lastLetter = letter;
19577             }
19578           });
19579           return letters;
19580         }
19581
19582         var GlyphSplitter_2 = GlyphSplitter;
19583         var GlyphSplitter_1 = /*#__PURE__*/Object.defineProperty({
19584           GlyphSplitter: GlyphSplitter_2
19585         }, '__esModule', {
19586           value: true
19587         });
19588
19589         function BaselineSplitter(word) {
19590           var letters = [];
19591           var lastLetter = '';
19592           word.split('').forEach(function (letter) {
19593             if (isArabic_1.isArabic(letter) && isArabic_1.isArabic(lastLetter)) {
19594               if (lastLetter.length && reference.tashkeel.indexOf(letter) > -1) {
19595                 letters[letters.length - 1] += letter;
19596               } else if (reference.lineBreakers.indexOf(lastLetter) > -1) {
19597                 letters.push(letter);
19598               } else {
19599                 letters[letters.length - 1] += letter;
19600               }
19601             } else {
19602               letters.push(letter);
19603             }
19604
19605             if (reference.tashkeel.indexOf(letter) === -1) {
19606               // don't allow tashkeel to hide line break
19607               lastLetter = letter;
19608             }
19609           });
19610           return letters;
19611         }
19612
19613         var BaselineSplitter_2 = BaselineSplitter;
19614         var BaselineSplitter_1 = /*#__PURE__*/Object.defineProperty({
19615           BaselineSplitter: BaselineSplitter_2
19616         }, '__esModule', {
19617           value: true
19618         });
19619
19620         function Normal(word, breakPresentationForm) {
19621           // default is to turn initial/isolated/medial/final presentation form to generic
19622           if (typeof breakPresentationForm === 'undefined') {
19623             breakPresentationForm = true;
19624           }
19625
19626           var returnable = '';
19627           word.split('').forEach(function (letter) {
19628             if (!isArabic_1.isArabic(letter)) {
19629               returnable += letter;
19630               return;
19631             }
19632
19633             for (var w = 0; w < reference.letterList.length; w++) {
19634               // ok so we are checking this potential lettertron
19635               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19636               var versions = Object.keys(letterForms);
19637
19638               for (var v = 0; v < versions.length; v++) {
19639                 var localVersion = letterForms[versions[v]];
19640
19641                 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19642                   // look at this embedded object
19643                   var embeddedForms = Object.keys(localVersion);
19644
19645                   for (var ef = 0; ef < embeddedForms.length; ef++) {
19646                     var form = localVersion[embeddedForms[ef]];
19647
19648                     if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19649                       // match
19650                       // console.log('embedded match');
19651                       if (form === letter) {
19652                         // match exact
19653                         if (breakPresentationForm && localVersion['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(embeddedForms[ef]) > -1) {
19654                           // replace presentation form
19655                           // console.log('keeping normal form of the letter');
19656                           if (_typeof(localVersion['normal']) === 'object') {
19657                             returnable += localVersion['normal'][0];
19658                           } else {
19659                             returnable += localVersion['normal'];
19660                           }
19661
19662                           return;
19663                         } // console.log('keeping this letter');
19664
19665
19666                         returnable += letter;
19667                         return;
19668                       } else if (_typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19669                         // match
19670                         returnable += form[0]; // console.log('added the first letter from the same array');
19671
19672                         return;
19673                       }
19674                     }
19675                   }
19676                 } else if (localVersion === letter) {
19677                   // match exact
19678                   if (breakPresentationForm && letterForms['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(versions[v]) > -1) {
19679                     // replace presentation form
19680                     // console.log('keeping normal form of the letter');
19681                     if (_typeof(letterForms['normal']) === 'object') {
19682                       returnable += letterForms['normal'][0];
19683                     } else {
19684                       returnable += letterForms['normal'];
19685                     }
19686
19687                     return;
19688                   } // console.log('keeping this letter');
19689
19690
19691                   returnable += letter;
19692                   return;
19693                 } else if (_typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19694                   // match
19695                   returnable += localVersion[0]; // console.log('added the first letter from the same array');
19696
19697                   return;
19698                 }
19699               }
19700             } // try ligatures
19701
19702
19703             for (var v2 = 0; v2 < reference.ligatureList.length; v2++) {
19704               var normalForm = reference.ligatureList[v2];
19705
19706               if (normalForm !== 'words') {
19707                 var ligForms = Object.keys(unicodeLigatures["default"][normalForm]);
19708
19709                 for (var f = 0; f < ligForms.length; f++) {
19710                   if (unicodeLigatures["default"][normalForm][ligForms[f]] === letter) {
19711                     returnable += normalForm;
19712                     return;
19713                   }
19714                 }
19715               }
19716             } // try words ligatures
19717
19718
19719             for (var v3 = 0; v3 < reference.ligatureWordList.length; v3++) {
19720               var _normalForm = reference.ligatureWordList[v3];
19721
19722               if (unicodeLigatures["default"].words[_normalForm] === letter) {
19723                 returnable += _normalForm;
19724                 return;
19725               }
19726             }
19727
19728             returnable += letter; // console.log('kept the letter')
19729           });
19730           return returnable;
19731         }
19732
19733         var Normal_1 = Normal;
19734         var Normalization = /*#__PURE__*/Object.defineProperty({
19735           Normal: Normal_1
19736         }, '__esModule', {
19737           value: true
19738         });
19739
19740         function CharShaper(letter, form) {
19741           if (!isArabic_1.isArabic(letter)) {
19742             // fail not Arabic
19743             throw new Error('Not Arabic');
19744           }
19745
19746           if (letter === "\u0621") {
19747             // hamza alone
19748             return "\u0621";
19749           }
19750
19751           for (var w = 0; w < reference.letterList.length; w++) {
19752             // ok so we are checking this potential lettertron
19753             var letterForms = unicodeArabic["default"][reference.letterList[w]];
19754             var versions = Object.keys(letterForms);
19755
19756             for (var v = 0; v < versions.length; v++) {
19757               var localVersion = letterForms[versions[v]];
19758
19759               if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19760                 if (versions.indexOf(form) > -1) {
19761                   return letterForms[form];
19762                 }
19763               } else if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19764                 // check embedded
19765                 var embeddedVersions = Object.keys(localVersion);
19766
19767                 for (var ev = 0; ev < embeddedVersions.length; ev++) {
19768                   if (localVersion[embeddedVersions[ev]] === letter || _typeof(localVersion[embeddedVersions[ev]]) === 'object' && localVersion[embeddedVersions[ev]].indexOf && localVersion[embeddedVersions[ev]].indexOf(letter) > -1) {
19769                     if (embeddedVersions.indexOf(form) > -1) {
19770                       return localVersion[form];
19771                     }
19772                   }
19773                 }
19774               }
19775             }
19776           }
19777         }
19778
19779         var CharShaper_2 = CharShaper;
19780         var CharShaper_1 = /*#__PURE__*/Object.defineProperty({
19781           CharShaper: CharShaper_2
19782         }, '__esModule', {
19783           value: true
19784         });
19785
19786         function WordShaper$1(word) {
19787           var state = 'initial';
19788           var output = '';
19789
19790           for (var w = 0; w < word.length; w++) {
19791             var nextLetter = ' ';
19792
19793             for (var nxw = w + 1; nxw < word.length; nxw++) {
19794               if (!isArabic_1.isArabic(word[nxw])) {
19795                 break;
19796               }
19797
19798               if (reference.tashkeel.indexOf(word[nxw]) === -1) {
19799                 nextLetter = word[nxw];
19800                 break;
19801               }
19802             }
19803
19804             if (!isArabic_1.isArabic(word[w]) || isArabic_1.isMath(word[w])) {
19805               // space or other non-Arabic
19806               output += word[w];
19807               state = 'initial';
19808             } else if (reference.tashkeel.indexOf(word[w]) > -1) {
19809               // tashkeel - add without changing state
19810               output += word[w];
19811             } else if (nextLetter === ' ' || // last Arabic letter in this word
19812             reference.lineBreakers.indexOf(word[w]) > -1) {
19813               // the current letter is known to break lines
19814               output += CharShaper_1.CharShaper(word[w], state === 'initial' ? 'isolated' : 'final');
19815               state = 'initial';
19816             } else if (reference.lams.indexOf(word[w]) > -1 && reference.alefs.indexOf(nextLetter) > -1) {
19817               // LA letters - advance an additional letter after this
19818               output += unicodeLigatures["default"][word[w] + nextLetter][state === 'initial' ? 'isolated' : 'final'];
19819
19820               while (word[w] !== nextLetter) {
19821                 w++;
19822               }
19823
19824               state = 'initial';
19825             } else {
19826               output += CharShaper_1.CharShaper(word[w], state);
19827               state = 'medial';
19828             }
19829           }
19830
19831           return output;
19832         }
19833
19834         var WordShaper_2 = WordShaper$1;
19835         var WordShaper_1 = /*#__PURE__*/Object.defineProperty({
19836           WordShaper: WordShaper_2
19837         }, '__esModule', {
19838           value: true
19839         });
19840
19841         function ParentLetter(letter) {
19842           if (!isArabic_1.isArabic(letter)) {
19843             throw new Error('Not an Arabic letter');
19844           }
19845
19846           for (var w = 0; w < reference.letterList.length; w++) {
19847             // ok so we are checking this potential lettertron
19848             var letterForms = unicodeArabic["default"][reference.letterList[w]];
19849             var versions = Object.keys(letterForms);
19850
19851             for (var v = 0; v < versions.length; v++) {
19852               var localVersion = letterForms[versions[v]];
19853
19854               if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19855                 // look at this embedded object
19856                 var embeddedForms = Object.keys(localVersion);
19857
19858                 for (var ef = 0; ef < embeddedForms.length; ef++) {
19859                   var form = localVersion[embeddedForms[ef]];
19860
19861                   if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19862                     // match
19863                     return localVersion;
19864                   }
19865                 }
19866               } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19867                 // match
19868                 return letterForms;
19869               }
19870             }
19871
19872             return null;
19873           }
19874         }
19875
19876         var ParentLetter_2 = ParentLetter;
19877
19878         function GrandparentLetter(letter) {
19879           if (!isArabic_1.isArabic(letter)) {
19880             throw new Error('Not an Arabic letter');
19881           }
19882
19883           for (var w = 0; w < reference.letterList.length; w++) {
19884             // ok so we are checking this potential lettertron
19885             var letterForms = unicodeArabic["default"][reference.letterList[w]];
19886             var versions = Object.keys(letterForms);
19887
19888             for (var v = 0; v < versions.length; v++) {
19889               var localVersion = letterForms[versions[v]];
19890
19891               if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19892                 // look at this embedded object
19893                 var embeddedForms = Object.keys(localVersion);
19894
19895                 for (var ef = 0; ef < embeddedForms.length; ef++) {
19896                   var form = localVersion[embeddedForms[ef]];
19897
19898                   if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19899                     // match
19900                     return letterForms;
19901                   }
19902                 }
19903               } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19904                 // match
19905                 return letterForms;
19906               }
19907             }
19908
19909             return null;
19910           }
19911         }
19912
19913         var GrandparentLetter_1 = GrandparentLetter;
19914         var ParentLetter_1 = /*#__PURE__*/Object.defineProperty({
19915           ParentLetter: ParentLetter_2,
19916           GrandparentLetter: GrandparentLetter_1
19917         }, '__esModule', {
19918           value: true
19919         });
19920
19921         isArabic_1.isArabic;
19922         GlyphSplitter_1.GlyphSplitter;
19923         BaselineSplitter_1.BaselineSplitter;
19924         Normalization.Normal;
19925         CharShaper_1.CharShaper;
19926         var WordShaper = WordShaper_1.WordShaper;
19927         ParentLetter_1.ParentLetter;
19928         ParentLetter_1.GrandparentLetter;
19929
19930         var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u07BF\u08A0–\u08BF]/;
19931         function fixRTLTextForSvg(inputText) {
19932           var ret = '',
19933               rtlBuffer = [];
19934           var arabicRegex = /[\u0600-\u06FF]/g;
19935           var arabicDiacritics = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06ED]/g;
19936           var arabicMath = /[\u0660-\u066C\u06F0-\u06F9]+/g;
19937           var thaanaVowel = /[\u07A6-\u07B0]/;
19938           var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/; // Arabic word shaping
19939
19940           if (arabicRegex.test(inputText)) {
19941             inputText = WordShaper(inputText);
19942           }
19943
19944           for (var n = 0; n < inputText.length; n++) {
19945             var c = inputText[n];
19946
19947             if (arabicMath.test(c)) {
19948               // Arabic numbers go LTR
19949               ret += rtlBuffer.reverse().join('');
19950               rtlBuffer = [c];
19951             } else {
19952               if (rtlBuffer.length && arabicMath.test(rtlBuffer[rtlBuffer.length - 1])) {
19953                 ret += rtlBuffer.reverse().join('');
19954                 rtlBuffer = [];
19955               }
19956
19957               if ((thaanaVowel.test(c) || hebrewSign.test(c) || arabicDiacritics.test(c)) && rtlBuffer.length) {
19958                 rtlBuffer[rtlBuffer.length - 1] += c;
19959               } else if (rtlRegex.test(c) // include Arabic presentation forms
19960               || c.charCodeAt(0) >= 64336 && c.charCodeAt(0) <= 65023 || c.charCodeAt(0) >= 65136 && c.charCodeAt(0) <= 65279) {
19961                 rtlBuffer.push(c);
19962               } else if (c === ' ' && rtlBuffer.length) {
19963                 // whitespace within RTL text
19964                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
19965               } else {
19966                 // non-RTL character
19967                 ret += rtlBuffer.reverse().join('') + c;
19968                 rtlBuffer = [];
19969               }
19970             }
19971           }
19972
19973           ret += rtlBuffer.reverse().join('');
19974           return ret;
19975         }
19976
19977         var propertyIsEnumerable = objectPropertyIsEnumerable.f;
19978
19979         // `Object.{ entries, values }` methods implementation
19980         var createMethod$1 = function (TO_ENTRIES) {
19981           return function (it) {
19982             var O = toIndexedObject(it);
19983             var keys = objectKeys(O);
19984             var length = keys.length;
19985             var i = 0;
19986             var result = [];
19987             var key;
19988             while (length > i) {
19989               key = keys[i++];
19990               if (!descriptors || propertyIsEnumerable.call(O, key)) {
19991                 result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
19992               }
19993             }
19994             return result;
19995           };
19996         };
19997
19998         var objectToArray = {
19999           // `Object.entries` method
20000           // https://tc39.es/ecma262/#sec-object.entries
20001           entries: createMethod$1(true),
20002           // `Object.values` method
20003           // https://tc39.es/ecma262/#sec-object.values
20004           values: createMethod$1(false)
20005         };
20006
20007         var $values = objectToArray.values;
20008
20009         // `Object.values` method
20010         // https://tc39.es/ecma262/#sec-object.values
20011         _export({ target: 'Object', stat: true }, {
20012           values: function values(O) {
20013             return $values(O);
20014           }
20015         });
20016
20017         // https://github.com/openstreetmap/iD/issues/772
20018         // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
20019         var _storage;
20020
20021         try {
20022           _storage = localStorage;
20023         } catch (e) {} // eslint-disable-line no-empty
20024
20025
20026         _storage = _storage || function () {
20027           var s = {};
20028           return {
20029             getItem: function getItem(k) {
20030               return s[k];
20031             },
20032             setItem: function setItem(k, v) {
20033               return s[k] = v;
20034             },
20035             removeItem: function removeItem(k) {
20036               return delete s[k];
20037             }
20038           };
20039         }(); //
20040         // corePreferences is an interface for persisting basic key-value strings
20041         // within and between iD sessions on the same site.
20042         //
20043
20044
20045         function corePreferences(k, v) {
20046           try {
20047             if (arguments.length === 1) return _storage.getItem(k);else if (v === null) _storage.removeItem(k);else _storage.setItem(k, v);
20048           } catch (e) {
20049             /* eslint-disable no-console */
20050             if (typeof console !== 'undefined') {
20051               console.error('localStorage quota exceeded');
20052             }
20053             /* eslint-enable no-console */
20054
20055           }
20056         }
20057
20058         var vparse = createCommonjsModule(function (module) {
20059           (function (window) {
20060
20061             function parseVersion(v) {
20062               var m = v.replace(/[^0-9.]/g, '').match(/[0-9]*\.|[0-9]+/g) || [];
20063               v = {
20064                 major: +m[0] || 0,
20065                 minor: +m[1] || 0,
20066                 patch: +m[2] || 0,
20067                 build: +m[3] || 0
20068               };
20069               v.isEmpty = !v.major && !v.minor && !v.patch && !v.build;
20070               v.parsed = [v.major, v.minor, v.patch, v.build];
20071               v.text = v.parsed.join('.');
20072               v.compare = compare;
20073               return v;
20074             }
20075
20076             function compare(v) {
20077               if (typeof v === 'string') {
20078                 v = parseVersion(v);
20079               }
20080
20081               for (var i = 0; i < 4; i++) {
20082                 if (this.parsed[i] !== v.parsed[i]) {
20083                   return this.parsed[i] > v.parsed[i] ? 1 : -1;
20084                 }
20085               }
20086
20087               return 0;
20088             }
20089             /* istanbul ignore next */
20090
20091
20092             if (module && 'object' === 'object') {
20093               module.exports = parseVersion;
20094             } else {
20095               window.parseVersion = parseVersion;
20096             }
20097           })(commonjsGlobal);
20098         });
20099
20100         var name = "iD";
20101         var version = "2.20.0";
20102         var description = "A friendly editor for OpenStreetMap";
20103         var main = "dist/iD.min.js";
20104         var repository = "github:openstreetmap/iD";
20105         var homepage = "https://github.com/openstreetmap/iD";
20106         var bugs = "https://github.com/openstreetmap/iD/issues";
20107         var keywords = ["editor","openstreetmap"];
20108         var license = "ISC";
20109         var scripts = {all:"npm-run-all -s clean build build:legacy dist",build:"npm-run-all -s build:css build:data build:dev","build:css":"node scripts/build_css.js","build:data":"shx mkdir -p dist/data && node scripts/build_data.js","build:dev":"rollup --config config/rollup.config.dev.js","build:legacy":"rollup --config config/rollup.config.legacy.js","build:stats":"rollup --config config/rollup.config.stats.js",clean:"shx rm -f dist/*.js dist/*.map dist/*.css dist/img/*.svg",dist:"npm-run-all -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:min:iD":"uglifyjs dist/iD.legacy.js --compress --mangle --output dist/iD.min.js","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",imagery:"node scripts/update_imagery.js",lint:"eslint scripts test/spec modules","lint:fix":"eslint scripts test/spec modules --fix",start:"npm-run-all -s build start:server",quickstart:"npm-run-all -s build:dev start:server","start:server":"node scripts/server.js",test:"npm-run-all -s lint build:css build:data build:legacy test:spec","test:spec":"phantomjs --web-security=no node_modules/mocha-phantomjs-core/mocha-phantomjs-core.js test/index.html spec",translations:"node scripts/update_locales.js"};
20110         var 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/togeojson":"0.16.0","@mapbox/vector-tile":"^1.3.1","@turf/bbox-clip":"^6.0.0","abortcontroller-polyfill":"^1.4.0","aes-js":"^3.1.2","alif-toolkit":"^1.2.9","core-js":"^3.6.5",diacritics:"1.3.0","fast-deep-equal":"~3.1.1","fast-json-stable-stringify":"2.1.0","lodash-es":"~4.17.15",marked:"~2.0.0","node-diff3":"2.1.0","osm-auth":"1.1.0",pannellum:"2.5.6","polygon-clipping":"~0.15.1",rbush:"3.0.1","whatwg-fetch":"^3.4.1","which-polygon":"2.2.0"};
20111         var devDependencies = {"@babel/core":"^7.11.6","@babel/preset-env":"^7.11.5","@fortawesome/fontawesome-svg-core":"^1.2.32","@fortawesome/free-brands-svg-icons":"~5.15.1","@fortawesome/free-regular-svg-icons":"~5.15.1","@fortawesome/free-solid-svg-icons":"~5.15.1","@ideditor/temaki":"~4.4.0","@mapbox/maki":"^6.0.0","@rollup/plugin-babel":"^5.2.1","@rollup/plugin-commonjs":"^17.0.0","@rollup/plugin-json":"^4.0.1","@rollup/plugin-node-resolve":"~11.2.0",autoprefixer:"^10.0.1",btoa:"^1.2.1",chai:"^4.1.0","cldr-core":"37.0.0","cldr-localenames-full":"37.0.0",colors:"^1.1.2","concat-files":"^0.1.1",d3:"~6.6.0","editor-layer-index":"github:osmlab/editor-layer-index#gh-pages",eslint:"^7.1.0",gaze:"^1.1.3",glob:"^7.1.0",happen:"^0.3.1","js-yaml":"^4.0.0","json-stringify-pretty-compact":"^3.0.0",mapillary_sprite_source:"^1.8.0","mapillary-js":"4.0.0",minimist:"^1.2.3",mocha:"^7.0.1","mocha-phantomjs-core":"^2.1.0","name-suggestion-index":"~6.0","node-fetch":"^2.6.1","npm-run-all":"^4.0.0","object-inspect":"1.10.3","osm-community-index":"~5.1.0","phantomjs-prebuilt":"~2.1.16",postcss:"^8.1.1","postcss-selector-prepend":"^0.5.0",rollup:"~2.52.8","rollup-plugin-includepaths":"~0.2.3","rollup-plugin-progress":"^1.1.1","rollup-plugin-visualizer":"~4.2.0",shelljs:"^0.8.0",shx:"^0.3.0",sinon:"7.5.0","sinon-chai":"^3.3.0",smash:"0.0","static-server":"^2.2.1","svg-sprite":"1.5.0","uglify-js":"~3.13.0",vparse:"~1.1.0"};
20112         var engines = {node:">=10"};
20113         var browserslist = ["> 0.2%, last 6 major versions, Firefox ESR, IE 11, maintained node versions"];
20114         var packageJSON = {
20115         name: name,
20116         version: version,
20117         description: description,
20118         main: main,
20119         repository: repository,
20120         homepage: homepage,
20121         bugs: bugs,
20122         keywords: keywords,
20123         license: license,
20124         scripts: scripts,
20125         dependencies: dependencies,
20126         devDependencies: devDependencies,
20127         engines: engines,
20128         browserslist: browserslist
20129         };
20130
20131         var _mainFileFetcher = coreFileFetcher(); // singleton
20132         // coreFileFetcher asynchronously fetches data from JSON files
20133         //
20134
20135         function coreFileFetcher() {
20136           var ociVersion = packageJSON.devDependencies['osm-community-index'];
20137           var v = vparse(ociVersion);
20138           var vMinor = "".concat(v.major, ".").concat(v.minor);
20139           var _this = {};
20140           var _inflight = {};
20141           var _fileMap = {
20142             'address_formats': 'data/address_formats.min.json',
20143             'deprecated': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/deprecated.min.json',
20144             'discarded': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/discarded.min.json',
20145             'imagery': 'data/imagery.min.json',
20146             'intro_graph': 'data/intro_graph.min.json',
20147             'keepRight': 'data/keepRight.min.json',
20148             'languages': 'data/languages.min.json',
20149             'locales': 'locales/index.min.json',
20150             'oci_defaults': "https://cdn.jsdelivr.net/npm/osm-community-index@".concat(vMinor, "/dist/defaults.min.json"),
20151             'oci_features': "https://cdn.jsdelivr.net/npm/osm-community-index@".concat(vMinor, "/dist/featureCollection.min.json"),
20152             'oci_resources': "https://cdn.jsdelivr.net/npm/osm-community-index@".concat(vMinor, "/dist/resources.min.json"),
20153             'preset_categories': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/preset_categories.min.json',
20154             'preset_defaults': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/preset_defaults.min.json',
20155             'preset_fields': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/fields.min.json',
20156             'preset_presets': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/presets.min.json',
20157             'phone_formats': 'data/phone_formats.min.json',
20158             'qa_data': 'data/qa_data.min.json',
20159             'shortcuts': 'data/shortcuts.min.json',
20160             'territory_languages': 'data/territory_languages.min.json',
20161             'wmf_sitematrix': 'https://cdn.jsdelivr.net/npm/wmf-sitematrix@0.1/wikipedia.min.json'
20162           };
20163           var _cachedData = {}; // expose the cache; useful for tests
20164
20165           _this.cache = function () {
20166             return _cachedData;
20167           }; // Returns a Promise to fetch data
20168           // (resolved with the data if we have it already)
20169
20170
20171           _this.get = function (which) {
20172             if (_cachedData[which]) {
20173               return Promise.resolve(_cachedData[which]);
20174             }
20175
20176             var file = _fileMap[which];
20177
20178             var url = file && _this.asset(file);
20179
20180             if (!url) {
20181               return Promise.reject("Unknown data file for \"".concat(which, "\""));
20182             }
20183
20184             var prom = _inflight[url];
20185
20186             if (!prom) {
20187               _inflight[url] = prom = utilFetchJson(url).then(function (result) {
20188                 delete _inflight[url];
20189
20190                 if (!result) {
20191                   throw new Error("No data loaded for \"".concat(which, "\""));
20192                 }
20193
20194                 _cachedData[which] = result;
20195                 return result;
20196               })["catch"](function (err) {
20197                 delete _inflight[url];
20198                 throw err;
20199               });
20200             }
20201
20202             return prom;
20203           }; // Accessor for the file map
20204
20205
20206           _this.fileMap = function (val) {
20207             if (!arguments.length) return _fileMap;
20208             _fileMap = val;
20209             return _this;
20210           };
20211
20212           var _assetPath = '';
20213
20214           _this.assetPath = function (val) {
20215             if (!arguments.length) return _assetPath;
20216             _assetPath = val;
20217             return _this;
20218           };
20219
20220           var _assetMap = {};
20221
20222           _this.assetMap = function (val) {
20223             if (!arguments.length) return _assetMap;
20224             _assetMap = val;
20225             return _this;
20226           };
20227
20228           _this.asset = function (val) {
20229             if (/^http(s)?:\/\//i.test(val)) return val;
20230             var filename = _assetPath + val;
20231             return _assetMap[filename] || filename;
20232           };
20233
20234           return _this;
20235         }
20236
20237         var getOwnPropertyNames = objectGetOwnPropertyNames.f;
20238         var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
20239         var defineProperty = objectDefineProperty.f;
20240         var trim$2 = stringTrim.trim;
20241
20242         var NUMBER = 'Number';
20243         var NativeNumber = global$2[NUMBER];
20244         var NumberPrototype = NativeNumber.prototype;
20245
20246         // Opera ~12 has broken Object#toString
20247         var BROKEN_CLASSOF = classofRaw(objectCreate(NumberPrototype)) == NUMBER;
20248
20249         // `ToNumber` abstract operation
20250         // https://tc39.es/ecma262/#sec-tonumber
20251         var toNumber$1 = function (argument) {
20252           var it = toPrimitive(argument, false);
20253           var first, third, radix, maxCode, digits, length, index, code;
20254           if (typeof it == 'string' && it.length > 2) {
20255             it = trim$2(it);
20256             first = it.charCodeAt(0);
20257             if (first === 43 || first === 45) {
20258               third = it.charCodeAt(2);
20259               if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
20260             } else if (first === 48) {
20261               switch (it.charCodeAt(1)) {
20262                 case 66: case 98: radix = 2; maxCode = 49; break; // fast equal of /^0b[01]+$/i
20263                 case 79: case 111: radix = 8; maxCode = 55; break; // fast equal of /^0o[0-7]+$/i
20264                 default: return +it;
20265               }
20266               digits = it.slice(2);
20267               length = digits.length;
20268               for (index = 0; index < length; index++) {
20269                 code = digits.charCodeAt(index);
20270                 // parseInt parses a string to a first unavailable symbol
20271                 // but ToNumber should return NaN if a string contains unavailable symbols
20272                 if (code < 48 || code > maxCode) return NaN;
20273               } return parseInt(digits, radix);
20274             }
20275           } return +it;
20276         };
20277
20278         // `Number` constructor
20279         // https://tc39.es/ecma262/#sec-number-constructor
20280         if (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
20281           var NumberWrapper = function Number(value) {
20282             var it = arguments.length < 1 ? 0 : value;
20283             var dummy = this;
20284             return dummy instanceof NumberWrapper
20285               // check on 1..constructor(foo) case
20286               && (BROKEN_CLASSOF ? fails(function () { NumberPrototype.valueOf.call(dummy); }) : classofRaw(dummy) != NUMBER)
20287                 ? inheritIfRequired(new NativeNumber(toNumber$1(it)), dummy, NumberWrapper) : toNumber$1(it);
20288           };
20289           for (var keys = descriptors ? getOwnPropertyNames(NativeNumber) : (
20290             // ES3:
20291             'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' +
20292             // ES2015 (in case, if modules with ES2015 Number statics required before):
20293             'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' +
20294             'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger,' +
20295             // ESNext
20296             'fromString,range'
20297           ).split(','), j = 0, key; keys.length > j; j++) {
20298             if (has$1(NativeNumber, key = keys[j]) && !has$1(NumberWrapper, key)) {
20299               defineProperty(NumberWrapper, key, getOwnPropertyDescriptor$2(NativeNumber, key));
20300             }
20301           }
20302           NumberWrapper.prototype = NumberPrototype;
20303           NumberPrototype.constructor = NumberWrapper;
20304           redefine(global$2, NUMBER, NumberWrapper);
20305         }
20306
20307         // `thisNumberValue` abstract operation
20308         // https://tc39.es/ecma262/#sec-thisnumbervalue
20309         var thisNumberValue = function (value) {
20310           if (typeof value != 'number' && classofRaw(value) != 'Number') {
20311             throw TypeError('Incorrect invocation');
20312           }
20313           return +value;
20314         };
20315
20316         // `String.prototype.repeat` method implementation
20317         // https://tc39.es/ecma262/#sec-string.prototype.repeat
20318         var stringRepeat = function repeat(count) {
20319           var str = String(requireObjectCoercible(this));
20320           var result = '';
20321           var n = toInteger(count);
20322           if (n < 0 || n == Infinity) throw RangeError('Wrong number of repetitions');
20323           for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) result += str;
20324           return result;
20325         };
20326
20327         var nativeToFixed = 1.0.toFixed;
20328         var floor = Math.floor;
20329
20330         var pow = function (x, n, acc) {
20331           return n === 0 ? acc : n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc);
20332         };
20333
20334         var log = function (x) {
20335           var n = 0;
20336           var x2 = x;
20337           while (x2 >= 4096) {
20338             n += 12;
20339             x2 /= 4096;
20340           }
20341           while (x2 >= 2) {
20342             n += 1;
20343             x2 /= 2;
20344           } return n;
20345         };
20346
20347         var multiply = function (data, n, c) {
20348           var index = -1;
20349           var c2 = c;
20350           while (++index < 6) {
20351             c2 += n * data[index];
20352             data[index] = c2 % 1e7;
20353             c2 = floor(c2 / 1e7);
20354           }
20355         };
20356
20357         var divide = function (data, n) {
20358           var index = 6;
20359           var c = 0;
20360           while (--index >= 0) {
20361             c += data[index];
20362             data[index] = floor(c / n);
20363             c = (c % n) * 1e7;
20364           }
20365         };
20366
20367         var dataToString = function (data) {
20368           var index = 6;
20369           var s = '';
20370           while (--index >= 0) {
20371             if (s !== '' || index === 0 || data[index] !== 0) {
20372               var t = String(data[index]);
20373               s = s === '' ? t : s + stringRepeat.call('0', 7 - t.length) + t;
20374             }
20375           } return s;
20376         };
20377
20378         var FORCED$4 = nativeToFixed && (
20379           0.00008.toFixed(3) !== '0.000' ||
20380           0.9.toFixed(0) !== '1' ||
20381           1.255.toFixed(2) !== '1.25' ||
20382           1000000000000000128.0.toFixed(0) !== '1000000000000000128'
20383         ) || !fails(function () {
20384           // V8 ~ Android 4.3-
20385           nativeToFixed.call({});
20386         });
20387
20388         // `Number.prototype.toFixed` method
20389         // https://tc39.es/ecma262/#sec-number.prototype.tofixed
20390         _export({ target: 'Number', proto: true, forced: FORCED$4 }, {
20391           toFixed: function toFixed(fractionDigits) {
20392             var number = thisNumberValue(this);
20393             var fractDigits = toInteger(fractionDigits);
20394             var data = [0, 0, 0, 0, 0, 0];
20395             var sign = '';
20396             var result = '0';
20397             var e, z, j, k;
20398
20399             if (fractDigits < 0 || fractDigits > 20) throw RangeError('Incorrect fraction digits');
20400             // eslint-disable-next-line no-self-compare -- NaN check
20401             if (number != number) return 'NaN';
20402             if (number <= -1e21 || number >= 1e21) return String(number);
20403             if (number < 0) {
20404               sign = '-';
20405               number = -number;
20406             }
20407             if (number > 1e-21) {
20408               e = log(number * pow(2, 69, 1)) - 69;
20409               z = e < 0 ? number * pow(2, -e, 1) : number / pow(2, e, 1);
20410               z *= 0x10000000000000;
20411               e = 52 - e;
20412               if (e > 0) {
20413                 multiply(data, 0, z);
20414                 j = fractDigits;
20415                 while (j >= 7) {
20416                   multiply(data, 1e7, 0);
20417                   j -= 7;
20418                 }
20419                 multiply(data, pow(10, j, 1), 0);
20420                 j = e - 1;
20421                 while (j >= 23) {
20422                   divide(data, 1 << 23);
20423                   j -= 23;
20424                 }
20425                 divide(data, 1 << j);
20426                 multiply(data, 1, 1);
20427                 divide(data, 2);
20428                 result = dataToString(data);
20429               } else {
20430                 multiply(data, 0, z);
20431                 multiply(data, 1 << -e, 0);
20432                 result = dataToString(data) + stringRepeat.call('0', fractDigits);
20433               }
20434             }
20435             if (fractDigits > 0) {
20436               k = result.length;
20437               result = sign + (k <= fractDigits
20438                 ? '0.' + stringRepeat.call('0', fractDigits - k) + result
20439                 : result.slice(0, k - fractDigits) + '.' + result.slice(k - fractDigits));
20440             } else {
20441               result = sign + result;
20442             } return result;
20443           }
20444         });
20445
20446         var globalIsFinite = global$2.isFinite;
20447
20448         // `Number.isFinite` method
20449         // https://tc39.es/ecma262/#sec-number.isfinite
20450         // eslint-disable-next-line es/no-number-isfinite -- safe
20451         var numberIsFinite = Number.isFinite || function isFinite(it) {
20452           return typeof it == 'number' && globalIsFinite(it);
20453         };
20454
20455         // `Number.isFinite` method
20456         // https://tc39.es/ecma262/#sec-number.isfinite
20457         _export({ target: 'Number', stat: true }, { isFinite: numberIsFinite });
20458
20459         var fromCharCode = String.fromCharCode;
20460         // eslint-disable-next-line es/no-string-fromcodepoint -- required for testing
20461         var $fromCodePoint = String.fromCodePoint;
20462
20463         // length should be 1, old FF problem
20464         var INCORRECT_LENGTH = !!$fromCodePoint && $fromCodePoint.length != 1;
20465
20466         // `String.fromCodePoint` method
20467         // https://tc39.es/ecma262/#sec-string.fromcodepoint
20468         _export({ target: 'String', stat: true, forced: INCORRECT_LENGTH }, {
20469           // eslint-disable-next-line no-unused-vars -- required for `.length`
20470           fromCodePoint: function fromCodePoint(x) {
20471             var elements = [];
20472             var length = arguments.length;
20473             var i = 0;
20474             var code;
20475             while (length > i) {
20476               code = +arguments[i++];
20477               if (toAbsoluteIndex(code, 0x10FFFF) !== code) throw RangeError(code + ' is not a valid code point');
20478               elements.push(code < 0x10000
20479                 ? fromCharCode(code)
20480                 : fromCharCode(((code -= 0x10000) >> 10) + 0xD800, code % 0x400 + 0xDC00)
20481               );
20482             } return elements.join('');
20483           }
20484         });
20485
20486         // @@search logic
20487         fixRegexpWellKnownSymbolLogic('search', function (SEARCH, nativeSearch, maybeCallNative) {
20488           return [
20489             // `String.prototype.search` method
20490             // https://tc39.es/ecma262/#sec-string.prototype.search
20491             function search(regexp) {
20492               var O = requireObjectCoercible(this);
20493               var searcher = regexp == undefined ? undefined : regexp[SEARCH];
20494               return searcher !== undefined ? searcher.call(regexp, O) : new RegExp(regexp)[SEARCH](String(O));
20495             },
20496             // `RegExp.prototype[@@search]` method
20497             // https://tc39.es/ecma262/#sec-regexp.prototype-@@search
20498             function (string) {
20499               var res = maybeCallNative(nativeSearch, this, string);
20500               if (res.done) return res.value;
20501
20502               var rx = anObject(this);
20503               var S = String(string);
20504
20505               var previousLastIndex = rx.lastIndex;
20506               if (!sameValue(previousLastIndex, 0)) rx.lastIndex = 0;
20507               var result = regexpExecAbstract(rx, S);
20508               if (!sameValue(rx.lastIndex, previousLastIndex)) rx.lastIndex = previousLastIndex;
20509               return result === null ? -1 : result.index;
20510             }
20511           ];
20512         });
20513
20514         var quickselect$1 = createCommonjsModule(function (module, exports) {
20515           (function (global, factory) {
20516             module.exports = factory() ;
20517           })(commonjsGlobal, function () {
20518
20519             function quickselect(arr, k, left, right, compare) {
20520               quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
20521             }
20522
20523             function quickselectStep(arr, k, left, right, compare) {
20524               while (right > left) {
20525                 if (right - left > 600) {
20526                   var n = right - left + 1;
20527                   var m = k - left + 1;
20528                   var z = Math.log(n);
20529                   var s = 0.5 * Math.exp(2 * z / 3);
20530                   var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
20531                   var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
20532                   var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
20533                   quickselectStep(arr, k, newLeft, newRight, compare);
20534                 }
20535
20536                 var t = arr[k];
20537                 var i = left;
20538                 var j = right;
20539                 swap(arr, left, k);
20540                 if (compare(arr[right], t) > 0) swap(arr, left, right);
20541
20542                 while (i < j) {
20543                   swap(arr, i, j);
20544                   i++;
20545                   j--;
20546
20547                   while (compare(arr[i], t) < 0) {
20548                     i++;
20549                   }
20550
20551                   while (compare(arr[j], t) > 0) {
20552                     j--;
20553                   }
20554                 }
20555
20556                 if (compare(arr[left], t) === 0) swap(arr, left, j);else {
20557                   j++;
20558                   swap(arr, j, right);
20559                 }
20560                 if (j <= k) left = j + 1;
20561                 if (k <= j) right = j - 1;
20562               }
20563             }
20564
20565             function swap(arr, i, j) {
20566               var tmp = arr[i];
20567               arr[i] = arr[j];
20568               arr[j] = tmp;
20569             }
20570
20571             function defaultCompare(a, b) {
20572               return a < b ? -1 : a > b ? 1 : 0;
20573             }
20574
20575             return quickselect;
20576           });
20577         });
20578
20579         var rbush_1 = rbush;
20580         var _default$1 = rbush;
20581
20582         function rbush(maxEntries, format) {
20583           if (!(this instanceof rbush)) return new rbush(maxEntries, format); // max entries in a node is 9 by default; min node fill is 40% for best performance
20584
20585           this._maxEntries = Math.max(4, maxEntries || 9);
20586           this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
20587
20588           if (format) {
20589             this._initFormat(format);
20590           }
20591
20592           this.clear();
20593         }
20594
20595         rbush.prototype = {
20596           all: function all() {
20597             return this._all(this.data, []);
20598           },
20599           search: function search(bbox) {
20600             var node = this.data,
20601                 result = [],
20602                 toBBox = this.toBBox;
20603             if (!intersects$1(bbox, node)) return result;
20604             var nodesToSearch = [],
20605                 i,
20606                 len,
20607                 child,
20608                 childBBox;
20609
20610             while (node) {
20611               for (i = 0, len = node.children.length; i < len; i++) {
20612                 child = node.children[i];
20613                 childBBox = node.leaf ? toBBox(child) : child;
20614
20615                 if (intersects$1(bbox, childBBox)) {
20616                   if (node.leaf) result.push(child);else if (contains$1(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
20617                 }
20618               }
20619
20620               node = nodesToSearch.pop();
20621             }
20622
20623             return result;
20624           },
20625           collides: function collides(bbox) {
20626             var node = this.data,
20627                 toBBox = this.toBBox;
20628             if (!intersects$1(bbox, node)) return false;
20629             var nodesToSearch = [],
20630                 i,
20631                 len,
20632                 child,
20633                 childBBox;
20634
20635             while (node) {
20636               for (i = 0, len = node.children.length; i < len; i++) {
20637                 child = node.children[i];
20638                 childBBox = node.leaf ? toBBox(child) : child;
20639
20640                 if (intersects$1(bbox, childBBox)) {
20641                   if (node.leaf || contains$1(bbox, childBBox)) return true;
20642                   nodesToSearch.push(child);
20643                 }
20644               }
20645
20646               node = nodesToSearch.pop();
20647             }
20648
20649             return false;
20650           },
20651           load: function load(data) {
20652             if (!(data && data.length)) return this;
20653
20654             if (data.length < this._minEntries) {
20655               for (var i = 0, len = data.length; i < len; i++) {
20656                 this.insert(data[i]);
20657               }
20658
20659               return this;
20660             } // recursively build the tree with the given data from scratch using OMT algorithm
20661
20662
20663             var node = this._build(data.slice(), 0, data.length - 1, 0);
20664
20665             if (!this.data.children.length) {
20666               // save as is if tree is empty
20667               this.data = node;
20668             } else if (this.data.height === node.height) {
20669               // split root if trees have the same height
20670               this._splitRoot(this.data, node);
20671             } else {
20672               if (this.data.height < node.height) {
20673                 // swap trees if inserted one is bigger
20674                 var tmpNode = this.data;
20675                 this.data = node;
20676                 node = tmpNode;
20677               } // insert the small tree into the large tree at appropriate level
20678
20679
20680               this._insert(node, this.data.height - node.height - 1, true);
20681             }
20682
20683             return this;
20684           },
20685           insert: function insert(item) {
20686             if (item) this._insert(item, this.data.height - 1);
20687             return this;
20688           },
20689           clear: function clear() {
20690             this.data = createNode$1([]);
20691             return this;
20692           },
20693           remove: function remove(item, equalsFn) {
20694             if (!item) return this;
20695             var node = this.data,
20696                 bbox = this.toBBox(item),
20697                 path = [],
20698                 indexes = [],
20699                 i,
20700                 parent,
20701                 index,
20702                 goingUp; // depth-first iterative tree traversal
20703
20704             while (node || path.length) {
20705               if (!node) {
20706                 // go up
20707                 node = path.pop();
20708                 parent = path[path.length - 1];
20709                 i = indexes.pop();
20710                 goingUp = true;
20711               }
20712
20713               if (node.leaf) {
20714                 // check current node
20715                 index = findItem$1(item, node.children, equalsFn);
20716
20717                 if (index !== -1) {
20718                   // item found, remove the item and condense tree upwards
20719                   node.children.splice(index, 1);
20720                   path.push(node);
20721
20722                   this._condense(path);
20723
20724                   return this;
20725                 }
20726               }
20727
20728               if (!goingUp && !node.leaf && contains$1(node, bbox)) {
20729                 // go down
20730                 path.push(node);
20731                 indexes.push(i);
20732                 i = 0;
20733                 parent = node;
20734                 node = node.children[0];
20735               } else if (parent) {
20736                 // go right
20737                 i++;
20738                 node = parent.children[i];
20739                 goingUp = false;
20740               } else node = null; // nothing found
20741
20742             }
20743
20744             return this;
20745           },
20746           toBBox: function toBBox(item) {
20747             return item;
20748           },
20749           compareMinX: compareNodeMinX$1,
20750           compareMinY: compareNodeMinY$1,
20751           toJSON: function toJSON() {
20752             return this.data;
20753           },
20754           fromJSON: function fromJSON(data) {
20755             this.data = data;
20756             return this;
20757           },
20758           _all: function _all(node, result) {
20759             var nodesToSearch = [];
20760
20761             while (node) {
20762               if (node.leaf) result.push.apply(result, node.children);else nodesToSearch.push.apply(nodesToSearch, node.children);
20763               node = nodesToSearch.pop();
20764             }
20765
20766             return result;
20767           },
20768           _build: function _build(items, left, right, height) {
20769             var N = right - left + 1,
20770                 M = this._maxEntries,
20771                 node;
20772
20773             if (N <= M) {
20774               // reached leaf level; return leaf
20775               node = createNode$1(items.slice(left, right + 1));
20776               calcBBox$1(node, this.toBBox);
20777               return node;
20778             }
20779
20780             if (!height) {
20781               // target height of the bulk-loaded tree
20782               height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
20783
20784               M = Math.ceil(N / Math.pow(M, height - 1));
20785             }
20786
20787             node = createNode$1([]);
20788             node.leaf = false;
20789             node.height = height; // split the items into M mostly square tiles
20790
20791             var N2 = Math.ceil(N / M),
20792                 N1 = N2 * Math.ceil(Math.sqrt(M)),
20793                 i,
20794                 j,
20795                 right2,
20796                 right3;
20797             multiSelect$1(items, left, right, N1, this.compareMinX);
20798
20799             for (i = left; i <= right; i += N1) {
20800               right2 = Math.min(i + N1 - 1, right);
20801               multiSelect$1(items, i, right2, N2, this.compareMinY);
20802
20803               for (j = i; j <= right2; j += N2) {
20804                 right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
20805
20806                 node.children.push(this._build(items, j, right3, height - 1));
20807               }
20808             }
20809
20810             calcBBox$1(node, this.toBBox);
20811             return node;
20812           },
20813           _chooseSubtree: function _chooseSubtree(bbox, node, level, path) {
20814             var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
20815
20816             while (true) {
20817               path.push(node);
20818               if (node.leaf || path.length - 1 === level) break;
20819               minArea = minEnlargement = Infinity;
20820
20821               for (i = 0, len = node.children.length; i < len; i++) {
20822                 child = node.children[i];
20823                 area = bboxArea$1(child);
20824                 enlargement = enlargedArea$1(bbox, child) - area; // choose entry with the least area enlargement
20825
20826                 if (enlargement < minEnlargement) {
20827                   minEnlargement = enlargement;
20828                   minArea = area < minArea ? area : minArea;
20829                   targetNode = child;
20830                 } else if (enlargement === minEnlargement) {
20831                   // otherwise choose one with the smallest area
20832                   if (area < minArea) {
20833                     minArea = area;
20834                     targetNode = child;
20835                   }
20836                 }
20837               }
20838
20839               node = targetNode || node.children[0];
20840             }
20841
20842             return node;
20843           },
20844           _insert: function _insert(item, level, isNode) {
20845             var toBBox = this.toBBox,
20846                 bbox = isNode ? item : toBBox(item),
20847                 insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
20848
20849             var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
20850
20851
20852             node.children.push(item);
20853             extend$2(node, bbox); // split on node overflow; propagate upwards if necessary
20854
20855             while (level >= 0) {
20856               if (insertPath[level].children.length > this._maxEntries) {
20857                 this._split(insertPath, level);
20858
20859                 level--;
20860               } else break;
20861             } // adjust bboxes along the insertion path
20862
20863
20864             this._adjustParentBBoxes(bbox, insertPath, level);
20865           },
20866           // split overflowed node into two
20867           _split: function _split(insertPath, level) {
20868             var node = insertPath[level],
20869                 M = node.children.length,
20870                 m = this._minEntries;
20871
20872             this._chooseSplitAxis(node, m, M);
20873
20874             var splitIndex = this._chooseSplitIndex(node, m, M);
20875
20876             var newNode = createNode$1(node.children.splice(splitIndex, node.children.length - splitIndex));
20877             newNode.height = node.height;
20878             newNode.leaf = node.leaf;
20879             calcBBox$1(node, this.toBBox);
20880             calcBBox$1(newNode, this.toBBox);
20881             if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
20882           },
20883           _splitRoot: function _splitRoot(node, newNode) {
20884             // split root node
20885             this.data = createNode$1([node, newNode]);
20886             this.data.height = node.height + 1;
20887             this.data.leaf = false;
20888             calcBBox$1(this.data, this.toBBox);
20889           },
20890           _chooseSplitIndex: function _chooseSplitIndex(node, m, M) {
20891             var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
20892             minOverlap = minArea = Infinity;
20893
20894             for (i = m; i <= M - m; i++) {
20895               bbox1 = distBBox$1(node, 0, i, this.toBBox);
20896               bbox2 = distBBox$1(node, i, M, this.toBBox);
20897               overlap = intersectionArea$1(bbox1, bbox2);
20898               area = bboxArea$1(bbox1) + bboxArea$1(bbox2); // choose distribution with minimum overlap
20899
20900               if (overlap < minOverlap) {
20901                 minOverlap = overlap;
20902                 index = i;
20903                 minArea = area < minArea ? area : minArea;
20904               } else if (overlap === minOverlap) {
20905                 // otherwise choose distribution with minimum area
20906                 if (area < minArea) {
20907                   minArea = area;
20908                   index = i;
20909                 }
20910               }
20911             }
20912
20913             return index;
20914           },
20915           // sorts node children by the best axis for split
20916           _chooseSplitAxis: function _chooseSplitAxis(node, m, M) {
20917             var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX$1,
20918                 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY$1,
20919                 xMargin = this._allDistMargin(node, m, M, compareMinX),
20920                 yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
20921             // otherwise it's already sorted by minY
20922
20923
20924             if (xMargin < yMargin) node.children.sort(compareMinX);
20925           },
20926           // total margin of all possible split distributions where each node is at least m full
20927           _allDistMargin: function _allDistMargin(node, m, M, compare) {
20928             node.children.sort(compare);
20929             var toBBox = this.toBBox,
20930                 leftBBox = distBBox$1(node, 0, m, toBBox),
20931                 rightBBox = distBBox$1(node, M - m, M, toBBox),
20932                 margin = bboxMargin$1(leftBBox) + bboxMargin$1(rightBBox),
20933                 i,
20934                 child;
20935
20936             for (i = m; i < M - m; i++) {
20937               child = node.children[i];
20938               extend$2(leftBBox, node.leaf ? toBBox(child) : child);
20939               margin += bboxMargin$1(leftBBox);
20940             }
20941
20942             for (i = M - m - 1; i >= m; i--) {
20943               child = node.children[i];
20944               extend$2(rightBBox, node.leaf ? toBBox(child) : child);
20945               margin += bboxMargin$1(rightBBox);
20946             }
20947
20948             return margin;
20949           },
20950           _adjustParentBBoxes: function _adjustParentBBoxes(bbox, path, level) {
20951             // adjust bboxes along the given tree path
20952             for (var i = level; i >= 0; i--) {
20953               extend$2(path[i], bbox);
20954             }
20955           },
20956           _condense: function _condense(path) {
20957             // go through the path, removing empty nodes and updating bboxes
20958             for (var i = path.length - 1, siblings; i >= 0; i--) {
20959               if (path[i].children.length === 0) {
20960                 if (i > 0) {
20961                   siblings = path[i - 1].children;
20962                   siblings.splice(siblings.indexOf(path[i]), 1);
20963                 } else this.clear();
20964               } else calcBBox$1(path[i], this.toBBox);
20965             }
20966           },
20967           _initFormat: function _initFormat(format) {
20968             // data format (minX, minY, maxX, maxY accessors)
20969             // uses eval-type function compilation instead of just accepting a toBBox function
20970             // because the algorithms are very sensitive to sorting functions performance,
20971             // so they should be dead simple and without inner calls
20972             var compareArr = ['return a', ' - b', ';'];
20973             this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
20974             this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
20975             this.toBBox = new Function('a', 'return {minX: a' + format[0] + ', minY: a' + format[1] + ', maxX: a' + format[2] + ', maxY: a' + format[3] + '};');
20976           }
20977         };
20978
20979         function findItem$1(item, items, equalsFn) {
20980           if (!equalsFn) return items.indexOf(item);
20981
20982           for (var i = 0; i < items.length; i++) {
20983             if (equalsFn(item, items[i])) return i;
20984           }
20985
20986           return -1;
20987         } // calculate node's bbox from bboxes of its children
20988
20989
20990         function calcBBox$1(node, toBBox) {
20991           distBBox$1(node, 0, node.children.length, toBBox, node);
20992         } // min bounding rectangle of node children from k to p-1
20993
20994
20995         function distBBox$1(node, k, p, toBBox, destNode) {
20996           if (!destNode) destNode = createNode$1(null);
20997           destNode.minX = Infinity;
20998           destNode.minY = Infinity;
20999           destNode.maxX = -Infinity;
21000           destNode.maxY = -Infinity;
21001
21002           for (var i = k, child; i < p; i++) {
21003             child = node.children[i];
21004             extend$2(destNode, node.leaf ? toBBox(child) : child);
21005           }
21006
21007           return destNode;
21008         }
21009
21010         function extend$2(a, b) {
21011           a.minX = Math.min(a.minX, b.minX);
21012           a.minY = Math.min(a.minY, b.minY);
21013           a.maxX = Math.max(a.maxX, b.maxX);
21014           a.maxY = Math.max(a.maxY, b.maxY);
21015           return a;
21016         }
21017
21018         function compareNodeMinX$1(a, b) {
21019           return a.minX - b.minX;
21020         }
21021
21022         function compareNodeMinY$1(a, b) {
21023           return a.minY - b.minY;
21024         }
21025
21026         function bboxArea$1(a) {
21027           return (a.maxX - a.minX) * (a.maxY - a.minY);
21028         }
21029
21030         function bboxMargin$1(a) {
21031           return a.maxX - a.minX + (a.maxY - a.minY);
21032         }
21033
21034         function enlargedArea$1(a, b) {
21035           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));
21036         }
21037
21038         function intersectionArea$1(a, b) {
21039           var minX = Math.max(a.minX, b.minX),
21040               minY = Math.max(a.minY, b.minY),
21041               maxX = Math.min(a.maxX, b.maxX),
21042               maxY = Math.min(a.maxY, b.maxY);
21043           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
21044         }
21045
21046         function contains$1(a, b) {
21047           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
21048         }
21049
21050         function intersects$1(a, b) {
21051           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
21052         }
21053
21054         function createNode$1(children) {
21055           return {
21056             children: children,
21057             height: 1,
21058             leaf: true,
21059             minX: Infinity,
21060             minY: Infinity,
21061             maxX: -Infinity,
21062             maxY: -Infinity
21063           };
21064         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
21065         // combines selection algorithm with binary divide & conquer approach
21066
21067
21068         function multiSelect$1(arr, left, right, n, compare) {
21069           var stack = [left, right],
21070               mid;
21071
21072           while (stack.length) {
21073             right = stack.pop();
21074             left = stack.pop();
21075             if (right - left <= n) continue;
21076             mid = left + Math.ceil((right - left) / n / 2) * n;
21077             quickselect$1(arr, mid, left, right, compare);
21078             stack.push(left, mid, mid, right);
21079           }
21080         }
21081         rbush_1["default"] = _default$1;
21082
21083         var lineclip_1 = lineclip$1;
21084         lineclip$1.polyline = lineclip$1;
21085         lineclip$1.polygon = polygonclip$1; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
21086         // handle polylines rather than just segments
21087
21088         function lineclip$1(points, bbox, result) {
21089           var len = points.length,
21090               codeA = bitCode$1(points[0], bbox),
21091               part = [],
21092               i,
21093               a,
21094               b,
21095               codeB,
21096               lastCode;
21097           if (!result) result = [];
21098
21099           for (i = 1; i < len; i++) {
21100             a = points[i - 1];
21101             b = points[i];
21102             codeB = lastCode = bitCode$1(b, bbox);
21103
21104             while (true) {
21105               if (!(codeA | codeB)) {
21106                 // accept
21107                 part.push(a);
21108
21109                 if (codeB !== lastCode) {
21110                   // segment went outside
21111                   part.push(b);
21112
21113                   if (i < len - 1) {
21114                     // start a new line
21115                     result.push(part);
21116                     part = [];
21117                   }
21118                 } else if (i === len - 1) {
21119                   part.push(b);
21120                 }
21121
21122                 break;
21123               } else if (codeA & codeB) {
21124                 // trivial reject
21125                 break;
21126               } else if (codeA) {
21127                 // a outside, intersect with clip edge
21128                 a = intersect$1(a, b, codeA, bbox);
21129                 codeA = bitCode$1(a, bbox);
21130               } else {
21131                 // b outside
21132                 b = intersect$1(a, b, codeB, bbox);
21133                 codeB = bitCode$1(b, bbox);
21134               }
21135             }
21136
21137             codeA = lastCode;
21138           }
21139
21140           if (part.length) result.push(part);
21141           return result;
21142         } // Sutherland-Hodgeman polygon clipping algorithm
21143
21144
21145         function polygonclip$1(points, bbox) {
21146           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
21147
21148           for (edge = 1; edge <= 8; edge *= 2) {
21149             result = [];
21150             prev = points[points.length - 1];
21151             prevInside = !(bitCode$1(prev, bbox) & edge);
21152
21153             for (i = 0; i < points.length; i++) {
21154               p = points[i];
21155               inside = !(bitCode$1(p, bbox) & edge); // if segment goes through the clip window, add an intersection
21156
21157               if (inside !== prevInside) result.push(intersect$1(prev, p, edge, bbox));
21158               if (inside) result.push(p); // add a point if it's inside
21159
21160               prev = p;
21161               prevInside = inside;
21162             }
21163
21164             points = result;
21165             if (!points.length) break;
21166           }
21167
21168           return result;
21169         } // intersect a segment against one of the 4 lines that make up the bbox
21170
21171
21172         function intersect$1(a, b, edge, bbox) {
21173           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
21174           edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
21175           edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
21176           edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
21177           null;
21178         } // bit code reflects the point position relative to the bbox:
21179         //         left  mid  right
21180         //    top  1001  1000  1010
21181         //    mid  0001  0000  0010
21182         // bottom  0101  0100  0110
21183
21184
21185         function bitCode$1(p, bbox) {
21186           var code = 0;
21187           if (p[0] < bbox[0]) code |= 1; // left
21188           else if (p[0] > bbox[2]) code |= 2; // right
21189
21190           if (p[1] < bbox[1]) code |= 4; // bottom
21191           else if (p[1] > bbox[3]) code |= 8; // top
21192
21193           return code;
21194         }
21195
21196         var whichPolygon_1 = whichPolygon;
21197
21198         function whichPolygon(data) {
21199           var bboxes = [];
21200
21201           for (var i = 0; i < data.features.length; i++) {
21202             var feature = data.features[i];
21203             var coords = feature.geometry.coordinates;
21204
21205             if (feature.geometry.type === 'Polygon') {
21206               bboxes.push(treeItem(coords, feature.properties));
21207             } else if (feature.geometry.type === 'MultiPolygon') {
21208               for (var j = 0; j < coords.length; j++) {
21209                 bboxes.push(treeItem(coords[j], feature.properties));
21210               }
21211             }
21212           }
21213
21214           var tree = rbush_1().load(bboxes);
21215
21216           function query(p, multi) {
21217             var output = [],
21218                 result = tree.search({
21219               minX: p[0],
21220               minY: p[1],
21221               maxX: p[0],
21222               maxY: p[1]
21223             });
21224
21225             for (var i = 0; i < result.length; i++) {
21226               if (insidePolygon(result[i].coords, p)) {
21227                 if (multi) output.push(result[i].props);else return result[i].props;
21228               }
21229             }
21230
21231             return multi && output.length ? output : null;
21232           }
21233
21234           query.tree = tree;
21235
21236           query.bbox = function queryBBox(bbox) {
21237             var output = [];
21238             var result = tree.search({
21239               minX: bbox[0],
21240               minY: bbox[1],
21241               maxX: bbox[2],
21242               maxY: bbox[3]
21243             });
21244
21245             for (var i = 0; i < result.length; i++) {
21246               if (polygonIntersectsBBox(result[i].coords, bbox)) {
21247                 output.push(result[i].props);
21248               }
21249             }
21250
21251             return output;
21252           };
21253
21254           return query;
21255         }
21256
21257         function polygonIntersectsBBox(polygon, bbox) {
21258           var bboxCenter = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
21259           if (insidePolygon(polygon, bboxCenter)) return true;
21260
21261           for (var i = 0; i < polygon.length; i++) {
21262             if (lineclip_1(polygon[i], bbox).length > 0) return true;
21263           }
21264
21265           return false;
21266         } // ray casting algorithm for detecting if point is in polygon
21267
21268
21269         function insidePolygon(rings, p) {
21270           var inside = false;
21271
21272           for (var i = 0, len = rings.length; i < len; i++) {
21273             var ring = rings[i];
21274
21275             for (var j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) {
21276               if (rayIntersect(p, ring[j], ring[k])) inside = !inside;
21277             }
21278           }
21279
21280           return inside;
21281         }
21282
21283         function rayIntersect(p, p1, p2) {
21284           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];
21285         }
21286
21287         function treeItem(coords, props) {
21288           var item = {
21289             minX: Infinity,
21290             minY: Infinity,
21291             maxX: -Infinity,
21292             maxY: -Infinity,
21293             coords: coords,
21294             props: props
21295           };
21296
21297           for (var i = 0; i < coords[0].length; i++) {
21298             var p = coords[0][i];
21299             item.minX = Math.min(item.minX, p[0]);
21300             item.minY = Math.min(item.minY, p[1]);
21301             item.maxX = Math.max(item.maxX, p[0]);
21302             item.maxY = Math.max(item.maxY, p[1]);
21303           }
21304
21305           return item;
21306         }
21307
21308         var type = "FeatureCollection";
21309         var features = [{
21310           type: "Feature",
21311           properties: {
21312             wikidata: "Q21",
21313             nameEn: "England",
21314             aliases: ["GB-ENG"],
21315             country: "GB",
21316             groups: ["Q23666", "Q3336843", "154", "150", "UN"],
21317             driveSide: "left",
21318             roadSpeedUnit: "mph",
21319             roadHeightUnit: "ft",
21320             callingCodes: ["44"]
21321           },
21322           geometry: {
21323             type: "MultiPolygon",
21324             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]]]]
21325           }
21326         }, {
21327           type: "Feature",
21328           properties: {
21329             wikidata: "Q22",
21330             nameEn: "Scotland",
21331             aliases: ["GB-SCT"],
21332             country: "GB",
21333             groups: ["Q23666", "Q3336843", "154", "150", "UN"],
21334             driveSide: "left",
21335             roadSpeedUnit: "mph",
21336             roadHeightUnit: "ft",
21337             callingCodes: ["44"]
21338           },
21339           geometry: {
21340             type: "MultiPolygon",
21341             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]]]]
21342           }
21343         }, {
21344           type: "Feature",
21345           properties: {
21346             wikidata: "Q25",
21347             nameEn: "Wales",
21348             aliases: ["GB-WLS"],
21349             country: "GB",
21350             groups: ["Q23666", "Q3336843", "154", "150", "UN"],
21351             driveSide: "left",
21352             roadSpeedUnit: "mph",
21353             roadHeightUnit: "ft",
21354             callingCodes: ["44"]
21355           },
21356           geometry: {
21357             type: "MultiPolygon",
21358             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]]]]
21359           }
21360         }, {
21361           type: "Feature",
21362           properties: {
21363             wikidata: "Q26",
21364             nameEn: "Northern Ireland",
21365             aliases: ["GB-NIR"],
21366             country: "GB",
21367             groups: ["Q22890", "Q3336843", "154", "150", "UN"],
21368             driveSide: "left",
21369             roadSpeedUnit: "mph",
21370             roadHeightUnit: "ft",
21371             callingCodes: ["44"]
21372           },
21373           geometry: {
21374             type: "MultiPolygon",
21375             coordinates: [[[[-6.34755, 55.49206], [-7.2471, 55.06933], [-7.34464, 55.04688], [-7.4033, 55.00391], [-7.40004, 54.94498], [-7.44404, 54.9403], [-7.4473, 54.87003], [-7.47626, 54.83084], [-7.54508, 54.79401], [-7.54671, 54.74606], [-7.64449, 54.75265], [-7.75041, 54.7103], [-7.83352, 54.73854], [-7.93293, 54.66603], [-7.70315, 54.62077], [-7.8596, 54.53671], [-7.99812, 54.54427], [-8.04538, 54.48941], [-8.179, 54.46763], [-8.04555, 54.36292], [-7.87101, 54.29299], [-7.8596, 54.21779], [-7.81397, 54.20159], [-7.69501, 54.20731], [-7.55812, 54.12239], [-7.4799, 54.12239], [-7.44567, 54.1539], [-7.32834, 54.11475], [-7.30553, 54.11869], [-7.34005, 54.14698], [-7.29157, 54.17191], [-7.28017, 54.16714], [-7.29687, 54.1354], [-7.29493, 54.12013], [-7.26316, 54.13863], [-7.25012, 54.20063], [-7.14908, 54.22732], [-7.19145, 54.31296], [-7.02034, 54.4212], [-6.87775, 54.34682], [-6.85179, 54.29176], [-6.81583, 54.22791], [-6.74575, 54.18788], [-6.70175, 54.20218], [-6.6382, 54.17071], [-6.66264, 54.0666], [-6.62842, 54.03503], [-6.47849, 54.06947], [-6.36605, 54.07234], [-6.36279, 54.11248], [-6.32694, 54.09337], [-6.29003, 54.11278], [-6.26218, 54.09785], [-5.83481, 53.87749], [-4.69044, 54.3629], [-6.34755, 55.49206]]]]
21376           }
21377         }, {
21378           type: "Feature",
21379           properties: {
21380             wikidata: "Q35",
21381             nameEn: "Denmark",
21382             country: "DK",
21383             groups: ["EU", "154", "150", "UN"],
21384             callingCodes: ["45"]
21385           },
21386           geometry: {
21387             type: "MultiPolygon",
21388             coordinates: [[[[12.16597, 56.60205], [10.40861, 58.38489], [7.28637, 57.35913], [8.02459, 55.09613], [8.45719, 55.06747], [8.55769, 54.91837], [8.63979, 54.91069], [8.76387, 54.8948], [8.81178, 54.90518], [8.92795, 54.90452], [9.04629, 54.87249], [9.14275, 54.87421], [9.20571, 54.85841], [9.24631, 54.84726], [9.23445, 54.83432], [9.2474, 54.8112], [9.32771, 54.80602], [9.33849, 54.80233], [9.36496, 54.81749], [9.38532, 54.83968], [9.41213, 54.84254], [9.43155, 54.82586], [9.4659, 54.83131], [9.58937, 54.88785], [9.62734, 54.88057], [9.61187, 54.85548], [9.73563, 54.8247], [9.89314, 54.84171], [10.16755, 54.73883], [10.31111, 54.65968], [11.00303, 54.63689], [11.90309, 54.38543], [12.85844, 54.82438], [13.93395, 54.84044], [15.36991, 54.73263], [15.79951, 55.54655], [14.89259, 55.5623], [14.28399, 55.1553], [12.84405, 55.13257], [12.60345, 55.42675], [12.88472, 55.63369], [12.6372, 55.91371], [12.65312, 56.04345], [12.07466, 56.29488], [12.16597, 56.60205]]]]
21389           }
21390         }, {
21391           type: "Feature",
21392           properties: {
21393             wikidata: "Q55",
21394             nameEn: "Netherlands",
21395             country: "NL",
21396             groups: ["EU", "155", "150", "UN"],
21397             callingCodes: ["31"]
21398           },
21399           geometry: {
21400             type: "MultiPolygon",
21401             coordinates: [[[[5.45168, 54.20039], [2.56575, 51.85301], [3.36263, 51.37112], [3.38696, 51.33436], [3.35847, 51.31572], [3.38289, 51.27331], [3.41704, 51.25933], [3.43488, 51.24135], [3.52698, 51.2458], [3.51502, 51.28697], [3.58939, 51.30064], [3.78999, 51.25766], [3.78783, 51.2151], [3.90125, 51.20371], [3.97889, 51.22537], [4.01957, 51.24504], [4.05165, 51.24171], [4.16721, 51.29348], [4.24024, 51.35371], [4.21923, 51.37443], [4.33265, 51.37687], [4.34086, 51.35738], [4.39292, 51.35547], [4.43777, 51.36989], [4.38064, 51.41965], [4.39747, 51.43316], [4.38122, 51.44905], [4.47736, 51.4778], [4.5388, 51.48184], [4.54675, 51.47265], [4.52846, 51.45002], [4.53521, 51.4243], [4.57489, 51.4324], [4.65442, 51.42352], [4.72935, 51.48424], [4.74578, 51.48937], [4.77321, 51.50529], [4.78803, 51.50284], [4.84139, 51.4799], [4.82409, 51.44736], [4.82946, 51.4213], [4.78314, 51.43319], [4.76577, 51.43046], [4.77229, 51.41337], [4.78941, 51.41102], [4.84988, 51.41502], [4.90016, 51.41404], [4.92152, 51.39487], [5.00393, 51.44406], [5.0106, 51.47167], [5.03281, 51.48679], [5.04774, 51.47022], [5.07891, 51.4715], [5.10456, 51.43163], [5.07102, 51.39469], [5.13105, 51.34791], [5.13377, 51.31592], [5.16222, 51.31035], [5.2002, 51.32243], [5.24244, 51.30495], [5.22542, 51.26888], [5.23814, 51.26064], [5.26461, 51.26693], [5.29716, 51.26104], [5.33886, 51.26314], [5.347, 51.27502], [5.41672, 51.26248], [5.4407, 51.28169], [5.46519, 51.2849], [5.48476, 51.30053], [5.515, 51.29462], [5.5569, 51.26544], [5.5603, 51.22249], [5.65145, 51.19788], [5.65528, 51.18736], [5.70344, 51.1829], [5.74617, 51.18928], [5.77735, 51.17845], [5.77697, 51.1522], [5.82564, 51.16753], [5.85508, 51.14445], [5.80798, 51.11661], [5.8109, 51.10861], [5.83226, 51.10585], [5.82921, 51.09328], [5.79903, 51.09371], [5.79835, 51.05834], [5.77258, 51.06196], [5.75961, 51.03113], [5.77688, 51.02483], [5.76242, 50.99703], [5.71864, 50.96092], [5.72875, 50.95428], [5.74752, 50.96202], [5.75927, 50.95601], [5.74644, 50.94723], [5.72545, 50.92312], [5.72644, 50.91167], [5.71626, 50.90796], [5.69858, 50.91046], [5.67886, 50.88142], [5.64504, 50.87107], [5.64009, 50.84742], [5.65259, 50.82309], [5.70118, 50.80764], [5.68995, 50.79641], [5.70107, 50.7827], [5.68091, 50.75804], [5.69469, 50.75529], [5.72216, 50.76398], [5.73904, 50.75674], [5.74356, 50.7691], [5.76533, 50.78159], [5.77513, 50.78308], [5.80673, 50.7558], [5.84548, 50.76542], [5.84888, 50.75448], [5.88734, 50.77092], [5.89129, 50.75125], [5.89132, 50.75124], [5.95942, 50.7622], [5.97545, 50.75441], [6.01976, 50.75398], [6.02624, 50.77453], [5.97497, 50.79992], [5.98404, 50.80988], [6.00462, 50.80065], [6.02328, 50.81694], [6.01921, 50.84435], [6.05623, 50.8572], [6.05702, 50.85179], [6.07431, 50.84674], [6.07693, 50.86025], [6.08805, 50.87223], [6.07486, 50.89307], [6.09297, 50.92066], [6.01615, 50.93367], [6.02697, 50.98303], [5.95282, 50.98728], [5.90296, 50.97356], [5.90493, 51.00198], [5.87849, 51.01969], [5.86735, 51.05182], [5.9134, 51.06736], [5.9541, 51.03496], [5.98292, 51.07469], [6.16706, 51.15677], [6.17384, 51.19589], [6.07889, 51.17038], [6.07889, 51.24432], [6.16977, 51.33169], [6.22674, 51.36135], [6.22641, 51.39948], [6.20654, 51.40049], [6.21724, 51.48568], [6.18017, 51.54096], [6.09055, 51.60564], [6.11759, 51.65609], [6.02767, 51.6742], [6.04091, 51.71821], [5.95003, 51.7493], [5.98665, 51.76944], [5.94568, 51.82786], [5.99848, 51.83195], [6.06705, 51.86136], [6.10337, 51.84829], [6.16902, 51.84094], [6.11551, 51.89769], [6.15349, 51.90439], [6.21443, 51.86801], [6.29872, 51.86801], [6.30593, 51.84998], [6.40704, 51.82771], [6.38815, 51.87257], [6.47179, 51.85395], [6.50231, 51.86313], [6.58556, 51.89386], [6.68386, 51.91861], [6.72319, 51.89518], [6.82357, 51.96711], [6.83035, 51.9905], [6.68128, 52.05052], [6.76117, 52.11895], [6.83984, 52.11728], [6.97189, 52.20329], [6.9897, 52.2271], [7.03729, 52.22695], [7.06365, 52.23789], [7.02703, 52.27941], [7.07044, 52.37805], [7.03417, 52.40237], [6.99041, 52.47235], [6.94293, 52.43597], [6.69507, 52.488], [6.71641, 52.62905], [6.77307, 52.65375], [7.04557, 52.63318], [7.07253, 52.81083], [7.21694, 53.00742], [7.17898, 53.13817], [7.22681, 53.18165], [7.21679, 53.20058], [7.19052, 53.31866], [7.00198, 53.32672], [6.91025, 53.44221], [5.45168, 54.20039]], [[4.93295, 51.44945], [4.95244, 51.45207], [4.9524, 51.45014], [4.93909, 51.44632], [4.93295, 51.44945]], [[4.91493, 51.4353], [4.91935, 51.43634], [4.92227, 51.44252], [4.91811, 51.44621], [4.92287, 51.44741], [4.92811, 51.4437], [4.92566, 51.44273], [4.92815, 51.43856], [4.92879, 51.44161], [4.93544, 51.44634], [4.94025, 51.44193], [4.93416, 51.44185], [4.93471, 51.43861], [4.94265, 51.44003], [4.93986, 51.43064], [4.92952, 51.42984], [4.92652, 51.43329], [4.91493, 51.4353]]]]
21402           }
21403         }, {
21404           type: "Feature",
21405           properties: {
21406             wikidata: "Q782",
21407             nameEn: "Hawaii",
21408             aliases: ["US-HI"],
21409             country: "US",
21410             groups: ["Q35657", "061", "009", "UN"],
21411             roadSpeedUnit: "mph",
21412             roadHeightUnit: "ft",
21413             callingCodes: ["1"]
21414           },
21415           geometry: {
21416             type: "MultiPolygon",
21417             coordinates: [[[[-177.8563, 29.18961], [-179.49839, 27.86265], [-151.6784, 9.55515], [-154.05867, 45.51124], [-177.5224, 27.7635], [-177.8563, 29.18961]]]]
21418           }
21419         }, {
21420           type: "Feature",
21421           properties: {
21422             wikidata: "Q797",
21423             nameEn: "Alaska",
21424             aliases: ["US-AK"],
21425             country: "US",
21426             groups: ["Q35657", "021", "003", "019", "UN"],
21427             roadSpeedUnit: "mph",
21428             roadHeightUnit: "ft",
21429             callingCodes: ["1"]
21430           },
21431           geometry: {
21432             type: "MultiPolygon",
21433             coordinates: [[[[169.34848, 52.47228], [180, 51.0171], [179.84401, 55.10087], [169.34848, 52.47228]]], [[[-168.95635, 65.98512], [-169.03888, 65.48473], [-172.76104, 63.77445], [-179.55295, 57.62081], [-179.55295, 50.81807], [-133.92876, 54.62289], [-130.61931, 54.70835], [-130.64499, 54.76912], [-130.44184, 54.85377], [-130.27203, 54.97174], [-130.18765, 55.07744], [-130.08035, 55.21556], [-129.97513, 55.28029], [-130.15373, 55.74895], [-130.00857, 55.91344], [-130.00093, 56.00325], [-130.10173, 56.12178], [-130.33965, 56.10849], [-130.77769, 56.36185], [-131.8271, 56.62247], [-133.38523, 58.42773], [-133.84645, 58.73543], [-134.27175, 58.8634], [-134.48059, 59.13231], [-134.55699, 59.1297], [-134.7047, 59.2458], [-135.00267, 59.28745], [-135.03069, 59.56208], [-135.48007, 59.79937], [-136.31566, 59.59083], [-136.22381, 59.55526], [-136.33727, 59.44466], [-136.47323, 59.46617], [-136.52365, 59.16752], [-136.82619, 59.16198], [-137.4925, 58.89415], [-137.60623, 59.24465], [-138.62145, 59.76431], [-138.71149, 59.90728], [-139.05365, 59.99655], [-139.20603, 60.08896], [-139.05831, 60.35205], [-139.68991, 60.33693], [-139.98024, 60.18027], [-140.45648, 60.30919], [-140.5227, 60.22077], [-141.00116, 60.30648], [-140.97446, 84.39275], [-168.25765, 71.99091], [-168.95635, 65.98512]]]]
21434           }
21435         }, {
21436           type: "Feature",
21437           properties: {
21438             wikidata: "Q3492",
21439             nameEn: "Sumatra",
21440             aliases: ["ID-SM"],
21441             country: "ID",
21442             groups: ["035", "142", "UN"],
21443             driveSide: "left",
21444             callingCodes: ["62"]
21445           },
21446           geometry: {
21447             type: "MultiPolygon",
21448             coordinates: [[[[109.82788, 2.86812], [110.90339, 7.52694], [105.01437, 3.24936], [104.56723, 1.44271], [104.34728, 1.33529], [104.12282, 1.27714], [104.03085, 1.26954], [103.74084, 1.12902], [103.66049, 1.18825], [103.56591, 1.19719], [103.03657, 1.30383], [96.11174, 6.69841], [74.28481, -3.17525], [102.92489, -8.17146], [106.32259, -5.50116], [106.38511, -5.16715], [109.17017, -4.07401], [109.3962, -2.07276], [108.50935, -2.01066], [107.94791, 1.06924], [109.82788, 2.86812]]]]
21449           }
21450         }, {
21451           type: "Feature",
21452           properties: {
21453             wikidata: "Q3757",
21454             nameEn: "Java",
21455             aliases: ["ID-JW"],
21456             country: "ID",
21457             groups: ["035", "142", "UN"],
21458             driveSide: "left",
21459             callingCodes: ["62"]
21460           },
21461           geometry: {
21462             type: "MultiPolygon",
21463             coordinates: [[[[109.17017, -4.07401], [106.38511, -5.16715], [106.32259, -5.50116], [102.92489, -8.17146], [116.22542, -10.49172], [114.39575, -8.2889], [114.42235, -8.09762], [114.92859, -7.49253], [116.33992, -7.56171], [116.58433, -5.30385], [109.17017, -4.07401]]]]
21464           }
21465         }, {
21466           type: "Feature",
21467           properties: {
21468             wikidata: "Q3795",
21469             nameEn: "Kalimantan",
21470             aliases: ["ID-KA"],
21471             country: "ID",
21472             groups: ["Q36117", "035", "142", "UN"],
21473             driveSide: "left",
21474             callingCodes: ["62"]
21475           },
21476           geometry: {
21477             type: "MultiPolygon",
21478             coordinates: [[[[120.02464, 2.83703], [118.06469, 4.16638], [117.67641, 4.16535], [117.47313, 4.18857], [117.25801, 4.35108], [115.90217, 4.37708], [115.58276, 3.93499], [115.53713, 3.14776], [115.11343, 2.82879], [115.1721, 2.49671], [114.80706, 2.21665], [114.80706, 1.92351], [114.57892, 1.5], [114.03788, 1.44787], [113.64677, 1.23933], [113.01448, 1.42832], [113.021, 1.57819], [112.48648, 1.56516], [112.2127, 1.44135], [112.15679, 1.17004], [111.94553, 1.12016], [111.82846, 0.99349], [111.55434, 0.97864], [111.22979, 1.08326], [110.62374, 0.873], [110.49182, 0.88088], [110.35354, 0.98869], [109.66397, 1.60425], [109.66397, 1.79972], [109.57923, 1.80624], [109.53794, 1.91771], [109.62558, 1.99182], [109.82788, 2.86812], [107.94791, 1.06924], [108.50935, -2.01066], [109.3962, -2.07276], [109.17017, -4.07401], [116.58433, -5.30385], [120.02464, 2.83703]]]]
21479           }
21480         }, {
21481           type: "Feature",
21482           properties: {
21483             wikidata: "Q3803",
21484             nameEn: "Lesser Sunda Islands",
21485             aliases: ["ID-NU"],
21486             country: "ID",
21487             groups: ["035", "142", "UN"],
21488             driveSide: "left",
21489             callingCodes: ["62"]
21490           },
21491           geometry: {
21492             type: "MultiPolygon",
21493             coordinates: [[[[116.96967, -8.01483], [114.92859, -7.49253], [114.42235, -8.09762], [114.39575, -8.2889], [116.22542, -10.49172], [122.14954, -11.52517], [125.68138, -9.85176], [125.09025, -9.46406], [124.97892, -9.19281], [125.04044, -9.17093], [125.09434, -9.19669], [125.18907, -9.16434], [125.18632, -9.03142], [125.11764, -8.96359], [124.97742, -9.08128], [124.94011, -8.85617], [124.46701, -9.13002], [124.45971, -9.30263], [124.38554, -9.3582], [124.35258, -9.43002], [124.3535, -9.48493], [124.28115, -9.50453], [124.28115, -9.42189], [124.21247, -9.36904], [124.14517, -9.42324], [124.10539, -9.41206], [124.04286, -9.34243], [124.04628, -9.22671], [124.33472, -9.11416], [124.92337, -8.75859], [125.87688, -7.49892], [116.96967, -8.01483]]]]
21494           }
21495         }, {
21496           type: "Feature",
21497           properties: {
21498             wikidata: "Q3812",
21499             nameEn: "Sulawesi",
21500             aliases: ["ID-SL"],
21501             country: "ID",
21502             groups: ["035", "142", "UN"],
21503             driveSide: "left",
21504             callingCodes: ["62"]
21505           },
21506           geometry: {
21507             type: "MultiPolygon",
21508             coordinates: [[[[128.34321, 3.90322], [126.69413, 6.02692], [119.56457, 0.90759], [116.58433, -5.30385], [116.33992, -7.56171], [116.96967, -8.01483], [125.87688, -7.49892], [123.78965, -0.86805], [128.34321, 3.90322]]]]
21509           }
21510         }, {
21511           type: "Feature",
21512           properties: {
21513             wikidata: "Q3827",
21514             nameEn: "Maluku Islands",
21515             aliases: ["ID-ML"],
21516             country: "ID",
21517             groups: ["035", "142", "UN"],
21518             driveSide: "left",
21519             callingCodes: ["62"]
21520           },
21521           geometry: {
21522             type: "MultiPolygon",
21523             coordinates: [[[[129.63187, 2.21409], [128.34321, 3.90322], [123.78965, -0.86805], [125.87688, -7.49892], [125.58506, -7.95311], [125.87691, -8.31789], [127.42116, -8.22471], [127.55165, -9.05052], [135.49042, -9.2276], [135.35517, -5.01442], [132.8312, -4.70282], [130.8468, -2.61103], [128.40647, -2.30349], [129.71519, -0.24692], [129.63187, 2.21409]]]]
21524           }
21525         }, {
21526           type: "Feature",
21527           properties: {
21528             wikidata: "Q3845",
21529             nameEn: "Western New Guinea",
21530             aliases: ["ID-PP"],
21531             country: "ID",
21532             groups: ["035", "142", "UN"],
21533             driveSide: "left",
21534             callingCodes: ["62"]
21535           },
21536           geometry: {
21537             type: "MultiPolygon",
21538             coordinates: [[[[135.49042, -9.2276], [141.01842, -9.35091], [141.01763, -6.90181], [140.90448, -6.85033], [140.85295, -6.72996], [140.99813, -6.3233], [141.02352, 0.08993], [129.63187, 2.21409], [129.71519, -0.24692], [128.40647, -2.30349], [130.8468, -2.61103], [132.8312, -4.70282], [135.35517, -5.01442], [135.49042, -9.2276]]]]
21539           }
21540         }, {
21541           type: "Feature",
21542           properties: {
21543             wikidata: "Q5765",
21544             nameEn: "Balearic Islands",
21545             aliases: ["ES-IB"],
21546             country: "ES",
21547             groups: ["EU", "039", "150", "UN"],
21548             callingCodes: ["34 971"]
21549           },
21550           geometry: {
21551             type: "MultiPolygon",
21552             coordinates: [[[[-2.27707, 35.35051], [5.10072, 39.89531], [3.75438, 42.33445], [-2.27707, 35.35051]]]]
21553           }
21554         }, {
21555           type: "Feature",
21556           properties: {
21557             wikidata: "Q5823",
21558             nameEn: "Ceuta",
21559             aliases: ["ES-CE"],
21560             country: "ES",
21561             groups: ["EA", "EU", "015", "002", "UN"],
21562             level: "subterritory",
21563             callingCodes: ["34"]
21564           },
21565           geometry: {
21566             type: "MultiPolygon",
21567             coordinates: [[[[-5.38491, 35.92591], [-5.37338, 35.88417], [-5.35844, 35.87375], [-5.34379, 35.8711], [-5.21179, 35.90091], [-5.38491, 35.92591]]]]
21568           }
21569         }, {
21570           type: "Feature",
21571           properties: {
21572             wikidata: "Q5831",
21573             nameEn: "Melilla",
21574             aliases: ["ES-ML"],
21575             country: "ES",
21576             groups: ["EA", "EU", "015", "002", "UN"],
21577             level: "subterritory",
21578             callingCodes: ["34"]
21579           },
21580           geometry: {
21581             type: "MultiPolygon",
21582             coordinates: [[[[-2.91909, 35.33927], [-2.96038, 35.31609], [-2.96648, 35.30475], [-2.96978, 35.29459], [-2.97035, 35.28852], [-2.96507, 35.28801], [-2.96826, 35.28296], [-2.96516, 35.27967], [-2.95431, 35.2728], [-2.95065, 35.26576], [-2.93893, 35.26737], [-2.92272, 35.27509], [-2.91909, 35.33927]]]]
21583           }
21584         }, {
21585           type: "Feature",
21586           properties: {
21587             wikidata: "Q7835",
21588             nameEn: "Crimea",
21589             country: "RU",
21590             groups: ["151", "150", "UN"],
21591             level: "subterritory",
21592             callingCodes: ["7"]
21593           },
21594           geometry: {
21595             type: "MultiPolygon",
21596             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]]]]
21597           }
21598         }, {
21599           type: "Feature",
21600           properties: {
21601             wikidata: "Q12837",
21602             nameEn: "Iberia",
21603             level: "sharedLandform"
21604           },
21605           geometry: null
21606         }, {
21607           type: "Feature",
21608           properties: {
21609             wikidata: "Q14056",
21610             nameEn: "Jan Mayen",
21611             aliases: ["NO-22"],
21612             country: "NO",
21613             groups: ["SJ", "154", "150", "UN"],
21614             level: "subterritory"
21615           },
21616           geometry: {
21617             type: "MultiPolygon",
21618             coordinates: [[[[-9.18243, 72.23144], [-10.71459, 70.09565], [-5.93364, 70.76368], [-9.18243, 72.23144]]]]
21619           }
21620         }, {
21621           type: "Feature",
21622           properties: {
21623             wikidata: "Q19188",
21624             nameEn: "Mainland China",
21625             country: "CN",
21626             groups: ["030", "142", "UN"],
21627             callingCodes: ["86"]
21628           },
21629           geometry: {
21630             type: "MultiPolygon",
21631             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]]]]
21632           }
21633         }, {
21634           type: "Feature",
21635           properties: {
21636             wikidata: "Q22890",
21637             nameEn: "Ireland",
21638             level: "sharedLandform"
21639           },
21640           geometry: null
21641         }, {
21642           type: "Feature",
21643           properties: {
21644             wikidata: "Q23666",
21645             nameEn: "Great Britain",
21646             country: "GB",
21647             level: "sharedLandform"
21648           },
21649           geometry: null
21650         }, {
21651           type: "Feature",
21652           properties: {
21653             wikidata: "Q23681",
21654             nameEn: "Northern Cyprus",
21655             groups: ["Q644636", "145", "142"],
21656             driveSide: "left",
21657             callingCodes: ["90 392"]
21658           },
21659           geometry: {
21660             type: "MultiPolygon",
21661             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]]]]
21662           }
21663         }, {
21664           type: "Feature",
21665           properties: {
21666             wikidata: "Q25231",
21667             nameEn: "Svalbard",
21668             aliases: ["NO-21"],
21669             country: "NO",
21670             groups: ["SJ", "154", "150", "UN"],
21671             level: "subterritory",
21672             callingCodes: ["47 79"]
21673           },
21674           geometry: {
21675             type: "MultiPolygon",
21676             coordinates: [[[[-7.49892, 77.24208], [32.07813, 72.01005], [36.85549, 84.09565], [-7.49892, 77.24208]]]]
21677           }
21678         }, {
21679           type: "Feature",
21680           properties: {
21681             wikidata: "Q25263",
21682             nameEn: "Azores",
21683             aliases: ["PT-20"],
21684             country: "PT",
21685             groups: ["Q3320166", "Q2914565", "Q105472", "EU", "039", "150", "UN"],
21686             callingCodes: ["351"]
21687           },
21688           geometry: {
21689             type: "MultiPolygon",
21690             coordinates: [[[[-23.12984, 40.26428], [-36.43765, 41.39418], [-22.54767, 33.34416], [-23.12984, 40.26428]]]]
21691           }
21692         }, {
21693           type: "Feature",
21694           properties: {
21695             wikidata: "Q25359",
21696             nameEn: "Navassa Island",
21697             aliases: ["UM-76"],
21698             country: "US",
21699             groups: ["UM", "Q1352230", "029", "003", "419", "019", "UN"],
21700             level: "subterritory",
21701             roadSpeedUnit: "mph",
21702             roadHeightUnit: "ft"
21703           },
21704           geometry: {
21705             type: "MultiPolygon",
21706             coordinates: [[[[-74.7289, 18.71009], [-75.71816, 18.46438], [-74.76465, 18.06252], [-74.7289, 18.71009]]]]
21707           }
21708         }, {
21709           type: "Feature",
21710           properties: {
21711             wikidata: "Q25396",
21712             nameEn: "Bonaire",
21713             aliases: ["BQ-BO", "NL-BQ1"],
21714             country: "NL",
21715             groups: ["Q1451600", "BQ", "029", "003", "419", "019", "UN"],
21716             level: "subterritory",
21717             callingCodes: ["599 7"]
21718           },
21719           geometry: {
21720             type: "MultiPolygon",
21721             coordinates: [[[[-67.89186, 12.4116], [-68.90012, 12.62309], [-68.33524, 11.78151], [-68.01417, 11.77722], [-67.89186, 12.4116]]]]
21722           }
21723         }, {
21724           type: "Feature",
21725           properties: {
21726             wikidata: "Q25528",
21727             nameEn: "Saba",
21728             aliases: ["BQ-SA", "NL-BQ2"],
21729             country: "NL",
21730             groups: ["Q1451600", "BQ", "029", "003", "419", "019", "UN"],
21731             level: "subterritory",
21732             callingCodes: ["599 4"]
21733           },
21734           geometry: {
21735             type: "MultiPolygon",
21736             coordinates: [[[[-63.07669, 17.79659], [-63.81314, 17.95045], [-63.22932, 17.32592], [-63.07669, 17.79659]]]]
21737           }
21738         }, {
21739           type: "Feature",
21740           properties: {
21741             wikidata: "Q26180",
21742             nameEn: "Sint Eustatius",
21743             aliases: ["BQ-SE", "NL-BQ3"],
21744             country: "NL",
21745             groups: ["Q1451600", "BQ", "029", "003", "419", "019", "UN"],
21746             level: "subterritory",
21747             callingCodes: ["599 3"]
21748           },
21749           geometry: {
21750             type: "MultiPolygon",
21751             coordinates: [[[[-63.07669, 17.79659], [-63.34999, 16.94218], [-62.76692, 17.64353], [-63.07669, 17.79659]]]]
21752           }
21753         }, {
21754           type: "Feature",
21755           properties: {
21756             wikidata: "Q26253",
21757             nameEn: "Madeira",
21758             aliases: ["PT-30"],
21759             country: "PT",
21760             groups: ["Q3320166", "Q2914565", "Q105472", "EU", "039", "150", "UN"],
21761             callingCodes: ["351"]
21762           },
21763           geometry: {
21764             type: "MultiPolygon",
21765             coordinates: [[[[-19.30302, 33.65304], [-16.04789, 29.65076], [-11.68307, 33.12333], [-19.30302, 33.65304]]]]
21766           }
21767         }, {
21768           type: "Feature",
21769           properties: {
21770             wikidata: "Q26927",
21771             nameEn: "Lakshadweep",
21772             aliases: ["IN-LD"],
21773             country: "IN",
21774             groups: ["034", "142", "UN"],
21775             driveSide: "left",
21776             callingCodes: ["91"]
21777           },
21778           geometry: {
21779             type: "MultiPolygon",
21780             coordinates: [[[[67.64074, 11.57295], [76.59015, 5.591], [72.67494, 13.58102], [67.64074, 11.57295]]]]
21781           }
21782         }, {
21783           type: "Feature",
21784           properties: {
21785             wikidata: "Q27329",
21786             nameEn: "Asian Russia",
21787             country: "RU",
21788             groups: ["142", "UN"],
21789             callingCodes: ["7"]
21790           },
21791           geometry: {
21792             type: "MultiPolygon",
21793             coordinates: [[[[-179.99933, 64.74703], [-172.76104, 63.77445], [-169.03888, 65.48473], [-168.95635, 65.98512], [-168.25765, 71.99091], [-179.9843, 71.90735], [-179.99933, 64.74703]]], [[[59.99809, 51.98263], [60.19925, 51.99173], [60.48915, 52.15175], [60.72581, 52.15538], [60.78201, 52.22067], [61.05417, 52.35096], [60.98021, 52.50068], [60.84709, 52.52228], [60.84118, 52.63912], [60.71693, 52.66245], [60.71989, 52.75923], [61.05842, 52.92217], [61.23462, 53.03227], [62.0422, 52.96105], [62.12799, 52.99133], [62.14574, 53.09626], [61.19024, 53.30536], [61.14291, 53.41481], [61.29082, 53.50992], [61.37957, 53.45887], [61.57185, 53.50112], [61.55706, 53.57144], [60.90626, 53.62937], [61.22574, 53.80268], [61.14283, 53.90063], [60.99796, 53.93699], [61.26863, 53.92797], [61.3706, 54.08464], [61.47603, 54.08048], [61.56941, 53.95703], [61.65318, 54.02445], [62.03913, 53.94768], [62.00966, 54.04134], [62.38535, 54.03961], [62.45931, 53.90737], [62.56876, 53.94047], [62.58651, 54.05871], [63.80604, 54.27079], [63.91224, 54.20013], [64.02715, 54.22679], [63.97686, 54.29763], [64.97216, 54.4212], [65.11033, 54.33028], [65.24663, 54.35721], [65.20174, 54.55216], [68.21308, 54.98645], [68.26661, 55.09226], [68.19206, 55.18823], [68.90865, 55.38148], [69.34224, 55.36344], [69.74917, 55.35545], [70.19179, 55.1476], [70.76493, 55.3027], [70.96009, 55.10558], [71.08288, 54.71253], [71.24185, 54.64965], [71.08706, 54.33376], [71.10379, 54.13326], [71.96141, 54.17736], [72.17477, 54.36303], [72.43415, 53.92685], [72.71026, 54.1161], [73.37963, 53.96132], [73.74778, 54.07194], [73.68921, 53.86522], [73.25412, 53.61532], [73.39218, 53.44623], [75.07405, 53.80831], [75.43398, 53.98652], [75.3668, 54.07439], [76.91052, 54.4677], [76.82266, 54.1798], [76.44076, 54.16017], [76.54243, 53.99329], [77.90383, 53.29807], [79.11255, 52.01171], [80.08138, 50.77658], [80.4127, 50.95581], [80.44819, 51.20855], [80.80318, 51.28262], [81.16999, 51.15662], [81.06091, 50.94833], [81.41248, 50.97524], [81.46581, 50.77658], [81.94999, 50.79307], [82.55443, 50.75412], [83.14607, 51.00796], [83.8442, 50.87375], [84.29385, 50.27257], [84.99198, 50.06793], [85.24047, 49.60239], [86.18709, 49.50259], [86.63674, 49.80136], [86.79056, 49.74787], [86.61307, 49.60239], [86.82606, 49.51796], [87.03071, 49.25142], [87.31465, 49.23603], [87.28386, 49.11626], [87.478, 49.07403], [87.48983, 49.13794], [87.81333, 49.17354], [87.98977, 49.18147], [88.15543, 49.30314], [88.17223, 49.46934], [88.42449, 49.48821], [88.82499, 49.44808], [89.70687, 49.72535], [89.59711, 49.90851], [91.86048, 50.73734], [92.07173, 50.69585], [92.44714, 50.78762], [93.01109, 50.79001], [92.99595, 50.63183], [94.30823, 50.57498], [94.39258, 50.22193], [94.49477, 50.17832], [94.6121, 50.04239], [94.97166, 50.04725], [95.02465, 49.96941], [95.74757, 49.97915], [95.80056, 50.04239], [96.97388, 49.88413], [97.24639, 49.74737], [97.56811, 49.84265], [97.56432, 49.92801], [97.76871, 49.99861], [97.85197, 49.91339], [98.29481, 50.33561], [98.31373, 50.4996], [98.06393, 50.61262], [97.9693, 50.78044], [98.01472, 50.86652], [97.83305, 51.00248], [98.05257, 51.46696], [98.22053, 51.46579], [98.33222, 51.71832], [98.74142, 51.8637], [98.87768, 52.14563], [99.27888, 51.96876], [99.75578, 51.90108], [99.89203, 51.74903], [100.61116, 51.73028], [101.39085, 51.45753], [101.5044, 51.50467], [102.14032, 51.35566], [102.32194, 50.67982], [102.71178, 50.38873], [103.70343, 50.13952], [105.32528, 50.4648], [106.05562, 50.40582], [106.07865, 50.33474], [106.47156, 50.31909], [106.49628, 50.32436], [106.51122, 50.34408], [106.58373, 50.34044], [106.80326, 50.30177], [107.00007, 50.1977], [107.1174, 50.04239], [107.36407, 49.97612], [107.96116, 49.93191], [107.95387, 49.66659], [108.27937, 49.53167], [108.53969, 49.32325], [109.18017, 49.34709], [109.51325, 49.22859], [110.24373, 49.16676], [110.39891, 49.25083], [110.64493, 49.1816], [113.02647, 49.60772], [113.20216, 49.83356], [114.325, 50.28098], [114.9703, 50.19254], [115.26068, 49.97367], [115.73602, 49.87688], [116.22402, 50.04477], [116.62502, 49.92919], [116.71193, 49.83813], [117.27597, 49.62544], [117.48208, 49.62324], [117.82343, 49.52696], [118.61623, 49.93809], [119.11003, 50.00276], [119.27996, 50.13348], [119.38598, 50.35162], [119.13553, 50.37412], [120.10963, 51.671], [120.65907, 51.93544], [120.77337, 52.20805], [120.61346, 52.32447], [120.71673, 52.54099], [120.46454, 52.63811], [120.04049, 52.58773], [120.0451, 52.7359], [120.85633, 53.28499], [121.39213, 53.31888], [122.35063, 53.49565], [122.85966, 53.47395], [123.26989, 53.54843], [123.86158, 53.49391], [124.46078, 53.21881], [125.17522, 53.20225], [125.6131, 53.07229], [126.558, 52.13738], [126.44606, 51.98254], [126.68349, 51.70607], [126.90369, 51.3238], [126.93135, 51.0841], [127.14586, 50.91152], [127.28165, 50.72075], [127.36335, 50.58306], [127.28765, 50.46585], [127.36009, 50.43787], [127.37384, 50.28393], [127.60515, 50.23503], [127.49299, 50.01251], [127.53516, 49.84306], [127.83476, 49.5748], [128.72896, 49.58676], [129.11153, 49.36813], [129.23232, 49.40353], [129.35317, 49.3481], [129.40398, 49.44194], [129.50685, 49.42398], [129.67598, 49.29596], [129.85416, 49.11067], [130.2355, 48.86741], [130.43232, 48.90844], [130.66946, 48.88251], [130.52147, 48.61745], [130.84462, 48.30942], [130.65103, 48.10052], [130.90915, 47.90623], [130.95985, 47.6957], [131.09871, 47.6852], [131.2635, 47.73325], [131.90448, 47.68011], [132.57309, 47.71741], [132.66989, 47.96491], [134.49516, 48.42884], [134.75328, 48.36763], [134.67098, 48.1564], [134.55508, 47.98651], [134.7671, 47.72051], [134.50898, 47.4812], [134.20016, 47.33458], [134.03538, 46.75668], [133.84104, 46.46681], [133.91496, 46.4274], [133.88097, 46.25066], [133.68047, 46.14697], [133.72695, 46.05576], [133.67569, 45.9759], [133.60442, 45.90053], [133.48457, 45.86203], [133.41083, 45.57723], [133.19419, 45.51913], [133.09279, 45.25693], [133.12293, 45.1332], [132.96373, 45.0212], [132.83978, 45.05916], [131.99417, 45.2567], [131.86903, 45.33636], [131.76532, 45.22609], [131.66852, 45.2196], [131.68466, 45.12374], [131.48415, 44.99513], [130.95639, 44.85154], [131.1108, 44.70266], [131.30365, 44.04262], [131.25484, 44.03131], [131.23583, 43.96085], [131.26176, 43.94011], [131.21105, 43.82383], [131.19492, 43.53047], [131.29402, 43.46695], [131.30324, 43.39498], [131.19031, 43.21385], [131.20414, 43.13654], [131.10274, 43.04734], [131.135, 42.94114], [131.02668, 42.91246], [131.02438, 42.86518], [130.66524, 42.84753], [130.44361, 42.76205], [130.40213, 42.70788], [130.56576, 42.68925], [130.62107, 42.58413], [130.55143, 42.52158], [130.56835, 42.43281], [130.60805, 42.4317], [130.64181, 42.41422], [130.66367, 42.38024], [130.65022, 42.32281], [131.95041, 41.5445], [140.9182, 45.92937], [145.82343, 44.571], [145.23667, 43.76813], [153.94307, 38.42848], [180, 62.52334], [180, 71.53642], [155.31937, 81.93282], [76.13964, 83.37843], [64.18965, 69.94255], [66.1708, 67.61252], [61.98014, 65.72191], [60.74386, 64.95767], [59.63945, 64.78384], [59.80579, 64.13948], [59.24834, 63.01859], [59.61398, 62.44915], [59.36223, 61.3882], [59.50685, 60.91162], [58.3853, 59.487], [59.15636, 59.14682], [59.40376, 58.45822], [58.71104, 58.07475], [58.81412, 57.71602], [58.13789, 57.68097], [58.07604, 57.08308], [57.28024, 56.87898], [57.51527, 56.08729], [59.28419, 56.15739], [59.49035, 55.60486], [58.81825, 55.03378], [57.25137, 55.26262], [57.14829, 54.84204], [57.95234, 54.39672], [59.95217, 54.85853], [59.70487, 54.14846], [58.94336, 53.953], [58.79644, 52.43392], [59.22409, 52.28437], [59.25033, 52.46803], [60.17516, 52.39457], [60.17253, 52.25814], [59.91279, 52.06924], [59.99809, 51.98263]]]]
21794           }
21795         }, {
21796           type: "Feature",
21797           properties: {
21798             wikidata: "Q34366",
21799             nameEn: "Tasmania",
21800             aliases: ["AU-TAS"],
21801             country: "AU",
21802             groups: ["053", "009", "UN"],
21803             driveSide: "left",
21804             callingCodes: ["61"]
21805           },
21806           geometry: {
21807             type: "MultiPolygon",
21808             coordinates: [[[[123.64533, -39.13605], [159.69067, -56.28945], [159.74028, -39.1978], [123.64533, -39.13605]]]]
21809           }
21810         }, {
21811           type: "Feature",
21812           properties: {
21813             wikidata: "Q34497",
21814             nameEn: "Saint Helena",
21815             aliases: ["SH-HL"],
21816             country: "GB",
21817             groups: ["SH", "BOTS", "011", "202", "002", "UN"],
21818             level: "subterritory",
21819             driveSide: "left",
21820             roadSpeedUnit: "mph",
21821             roadHeightUnit: "ft",
21822             callingCodes: ["290"]
21823           },
21824           geometry: {
21825             type: "MultiPolygon",
21826             coordinates: [[[[-8.3824, -13.9131], [-6.17428, -19.07236], [-3.29308, -15.22647], [-8.3824, -13.9131]]]]
21827           }
21828         }, {
21829           type: "Feature",
21830           properties: {
21831             wikidata: "Q35657",
21832             nameEn: "US States",
21833             country: "US",
21834             level: "subcountryGroup"
21835           },
21836           geometry: null
21837         }, {
21838           type: "Feature",
21839           properties: {
21840             wikidata: "Q36117",
21841             nameEn: "Borneo",
21842             level: "sharedLandform"
21843           },
21844           geometry: null
21845         }, {
21846           type: "Feature",
21847           properties: {
21848             wikidata: "Q36678",
21849             nameEn: "West Bank",
21850             country: "PS",
21851             groups: ["145", "142"],
21852             callingCodes: ["970"]
21853           },
21854           geometry: {
21855             type: "MultiPolygon",
21856             coordinates: [[[[35.47672, 31.49578], [35.55941, 31.76535], [35.52758, 31.9131], [35.54375, 31.96587], [35.52012, 32.04076], [35.57111, 32.21877], [35.55807, 32.38674], [35.42078, 32.41562], [35.41048, 32.43706], [35.41598, 32.45593], [35.42034, 32.46009], [35.40224, 32.50136], [35.35212, 32.52047], [35.30685, 32.51024], [35.29306, 32.50947], [35.25049, 32.52453], [35.2244, 32.55289], [35.15937, 32.50466], [35.10882, 32.4757], [35.10024, 32.47856], [35.09236, 32.47614], [35.08564, 32.46948], [35.07059, 32.4585], [35.05423, 32.41754], [35.05311, 32.4024], [35.0421, 32.38242], [35.05142, 32.3667], [35.04243, 32.35008], [35.01772, 32.33863], [35.01119, 32.28684], [35.02939, 32.2671], [35.01841, 32.23981], [34.98885, 32.20758], [34.95703, 32.19522], [34.96009, 32.17503], [34.99039, 32.14626], [34.98507, 32.12606], [34.99437, 32.10962], [34.9863, 32.09551], [35.00261, 32.027], [34.98682, 31.96935], [35.00124, 31.93264], [35.03489, 31.92448], [35.03978, 31.89276], [35.03489, 31.85919], [34.99712, 31.85569], [34.9724, 31.83352], [35.01978, 31.82944], [35.05617, 31.85685], [35.07677, 31.85627], [35.14174, 31.81325], [35.18603, 31.80901], [35.18169, 31.82542], [35.19461, 31.82687], [35.21469, 31.81835], [35.216, 31.83894], [35.21128, 31.863], [35.20381, 31.86716], [35.20673, 31.88151], [35.20791, 31.8821], [35.20945, 31.8815], [35.21016, 31.88237], [35.21276, 31.88153], [35.2136, 31.88241], [35.22014, 31.88264], [35.22294, 31.87889], [35.22567, 31.86745], [35.22817, 31.8638], [35.2249, 31.85433], [35.2304, 31.84222], [35.24816, 31.8458], [35.25753, 31.8387], [35.251, 31.83085], [35.26404, 31.82567], [35.25573, 31.81362], [35.26058, 31.79064], [35.25225, 31.7678], [35.26319, 31.74846], [35.25182, 31.73945], [35.24981, 31.72543], [35.2438, 31.7201], [35.24315, 31.71244], [35.23972, 31.70896], [35.22392, 31.71899], [35.21937, 31.71578], [35.20538, 31.72388], [35.18023, 31.72067], [35.16478, 31.73242], [35.15474, 31.73352], [35.15119, 31.73634], [35.13931, 31.73012], [35.12933, 31.7325], [35.11895, 31.71454], [35.10782, 31.71594], [35.08226, 31.69107], [35.00879, 31.65426], [34.95249, 31.59813], [34.9415, 31.55601], [34.94356, 31.50743], [34.93258, 31.47816], [34.89756, 31.43891], [34.87833, 31.39321], [34.88932, 31.37093], [34.92571, 31.34337], [35.02459, 31.35979], [35.13033, 31.3551], [35.22921, 31.37445], [35.39675, 31.49572], [35.47672, 31.49578]]]]
21857           }
21858         }, {
21859           type: "Feature",
21860           properties: {
21861             wikidata: "Q37362",
21862             nameEn: "Akrotiri and Dhekelia",
21863             aliases: ["SBA"],
21864             country: "GB"
21865           },
21866           geometry: null
21867         }, {
21868           type: "Feature",
21869           properties: {
21870             wikidata: "Q38095",
21871             nameEn: "Gal\xE1pagos Islands",
21872             aliases: ["EC-W"],
21873             country: "EC",
21874             groups: ["005", "419", "019", "UN"],
21875             callingCodes: ["593"]
21876           },
21877           geometry: {
21878             type: "MultiPolygon",
21879             coordinates: [[[[-93.12365, 2.64343], [-92.46744, -2.52874], [-87.07749, -0.8849], [-93.12365, 2.64343]]]]
21880           }
21881         }, {
21882           type: "Feature",
21883           properties: {
21884             wikidata: "Q39760",
21885             nameEn: "Gaza Strip",
21886             country: "PS",
21887             groups: ["145", "142"],
21888             callingCodes: ["970"]
21889           },
21890           geometry: {
21891             type: "MultiPolygon",
21892             coordinates: [[[[34.052, 31.46619], [34.21853, 31.32363], [34.23572, 31.2966], [34.24012, 31.29591], [34.26742, 31.21998], [34.29417, 31.24194], [34.36523, 31.28963], [34.37381, 31.30598], [34.36505, 31.36404], [34.40077, 31.40926], [34.48892, 31.48365], [34.56797, 31.54197], [34.48681, 31.59711], [34.29262, 31.70393], [34.052, 31.46619]]]]
21893           }
21894         }, {
21895           type: "Feature",
21896           properties: {
21897             wikidata: "Q40888",
21898             nameEn: "Andaman and Nicobar Islands",
21899             aliases: ["IN-AN"],
21900             country: "IN",
21901             groups: ["034", "142", "UN"],
21902             driveSide: "left",
21903             callingCodes: ["91"]
21904           },
21905           geometry: {
21906             type: "MultiPolygon",
21907             coordinates: [[[[94.42132, 5.96581], [94.6371, 13.81803], [86.7822, 13.41052], [94.42132, 5.96581]]]]
21908           }
21909         }, {
21910           type: "Feature",
21911           properties: {
21912             wikidata: "Q41684",
21913             nameEn: "Stewart Island",
21914             country: "NZ",
21915             groups: ["053", "009", "UN"],
21916             driveSide: "left",
21917             callingCodes: ["64"]
21918           },
21919           geometry: {
21920             type: "MultiPolygon",
21921             coordinates: [[[[166.59185, -47.61313], [169.70504, -47.56021], [167.52103, -46.41337], [166.59185, -47.61313]]]]
21922           }
21923         }, {
21924           type: "Feature",
21925           properties: {
21926             wikidata: "Q43296",
21927             nameEn: "Wake Island",
21928             aliases: ["WK", "WAK", "WKUM", "872", "UM-79"],
21929             country: "US",
21930             groups: ["UM", "Q1352230", "057", "009", "UN"],
21931             level: "subterritory",
21932             roadSpeedUnit: "mph",
21933             roadHeightUnit: "ft",
21934             callingCodes: ["1"]
21935           },
21936           geometry: {
21937             type: "MultiPolygon",
21938             coordinates: [[[[167.34779, 18.97692], [166.67967, 20.14834], [165.82549, 18.97692], [167.34779, 18.97692]]]]
21939           }
21940         }, {
21941           type: "Feature",
21942           properties: {
21943             wikidata: "Q46275",
21944             nameEn: "New Zealand Subantarctic Islands",
21945             country: "NZ",
21946             groups: ["Q851132", "053", "009", "UN"],
21947             driveSide: "left"
21948           },
21949           geometry: {
21950             type: "MultiPolygon",
21951             coordinates: [[[[164.30551, -47.88072], [161.96603, -56.07661], [179.49541, -50.04657], [179.49541, -47.2902], [169.91032, -47.66283], [164.30551, -47.88072]]]]
21952           }
21953         }, {
21954           type: "Feature",
21955           properties: {
21956             wikidata: "Q46395",
21957             nameEn: "British Overseas Territories",
21958             aliases: ["BOTS", "UKOTS"],
21959             country: "GB",
21960             level: "subcountryGroup"
21961           },
21962           geometry: null
21963         }, {
21964           type: "Feature",
21965           properties: {
21966             wikidata: "Q46772",
21967             nameEn: "Kerguelen Islands",
21968             country: "FR",
21969             groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
21970             level: "subterritory"
21971           },
21972           geometry: {
21973             type: "MultiPolygon",
21974             coordinates: [[[[61.9216, -49.39746], [70.67507, -51.14192], [74.25129, -45.45074], [61.9216, -49.39746]]]]
21975           }
21976         }, {
21977           type: "Feature",
21978           properties: {
21979             wikidata: "Q46879",
21980             nameEn: "Baker Island",
21981             aliases: ["UM-81"],
21982             country: "US",
21983             groups: ["UM", "Q1352230", "061", "009", "UN"],
21984             level: "subterritory",
21985             roadSpeedUnit: "mph",
21986             roadHeightUnit: "ft"
21987           },
21988           geometry: {
21989             type: "MultiPolygon",
21990             coordinates: [[[[-175.33482, -1.40631], [-175.31323, 0.5442], [-177.91421, 0.39582], [-175.33482, -1.40631]]]]
21991           }
21992         }, {
21993           type: "Feature",
21994           properties: {
21995             wikidata: "Q47863",
21996             nameEn: "Midway Atoll",
21997             aliases: ["MI", "MID", "MIUM", "488", "UM-71"],
21998             country: "US",
21999             groups: ["UM", "Q1352230", "061", "009", "UN"],
22000             level: "subterritory",
22001             roadSpeedUnit: "mph",
22002             roadHeightUnit: "ft",
22003             callingCodes: ["1"]
22004           },
22005           geometry: {
22006             type: "MultiPolygon",
22007             coordinates: [[[[-176.29741, 29.09786], [-177.77531, 29.29793], [-177.5224, 27.7635], [-176.29741, 29.09786]]]]
22008           }
22009         }, {
22010           type: "Feature",
22011           properties: {
22012             wikidata: "Q62218",
22013             nameEn: "Jarvis Island",
22014             aliases: ["UM-86"],
22015             country: "US",
22016             groups: ["UM", "Q1352230", "061", "009", "UN"],
22017             level: "subterritory",
22018             roadSpeedUnit: "mph",
22019             roadHeightUnit: "ft"
22020           },
22021           geometry: {
22022             type: "MultiPolygon",
22023             coordinates: [[[[-160.42921, -1.4364], [-159.12443, 0.19975], [-160.38779, 0.30331], [-160.42921, -1.4364]]]]
22024           }
22025         }, {
22026           type: "Feature",
22027           properties: {
22028             wikidata: "Q105472",
22029             nameEn: "Macaronesia",
22030             level: "sharedLandform"
22031           },
22032           geometry: null
22033         }, {
22034           type: "Feature",
22035           properties: {
22036             wikidata: "Q114935",
22037             nameEn: "Kermadec Islands",
22038             country: "NZ",
22039             groups: ["Q851132", "053", "009", "UN"],
22040             driveSide: "left",
22041             callingCodes: ["64"]
22042           },
22043           geometry: {
22044             type: "MultiPolygon",
22045             coordinates: [[[[-174.40891, -29.09438], [-180, -24.21376], [-179.96512, -35.00791], [-174.40891, -29.09438]]]]
22046           }
22047         }, {
22048           type: "Feature",
22049           properties: {
22050             wikidata: "Q115459",
22051             nameEn: "Chatham Islands",
22052             aliases: ["NZ-CIT"],
22053             country: "NZ",
22054             groups: ["Q851132", "053", "009", "UN"],
22055             driveSide: "left",
22056             callingCodes: ["64"]
22057           },
22058           geometry: {
22059             type: "MultiPolygon",
22060             coordinates: [[[[-179.93224, -45.18423], [-172.47015, -45.17912], [-176.30998, -41.38382], [-179.93224, -45.18423]]]]
22061           }
22062         }, {
22063           type: "Feature",
22064           properties: {
22065             wikidata: "Q118863",
22066             nameEn: "North Island",
22067             country: "NZ",
22068             groups: ["053", "009", "UN"],
22069             driveSide: "left",
22070             callingCodes: ["64"]
22071           },
22072           geometry: {
22073             type: "MultiPolygon",
22074             coordinates: [[[[179.49541, -47.2902], [179.49541, -36.79303], [174.17679, -32.62487], [170.27492, -36.38133], [174.58663, -40.80446], [174.46634, -41.55028], [179.49541, -47.2902]]]]
22075           }
22076         }, {
22077           type: "Feature",
22078           properties: {
22079             wikidata: "Q120755",
22080             nameEn: "South Island",
22081             country: "NZ",
22082             groups: ["053", "009", "UN"],
22083             driveSide: "left",
22084             callingCodes: ["64"]
22085           },
22086           geometry: {
22087             type: "MultiPolygon",
22088             coordinates: [[[[169.70504, -47.56021], [179.49541, -47.2902], [174.46634, -41.55028], [174.58663, -40.80446], [170.27492, -36.38133], [166.56976, -39.94841], [164.8365, -46.0205], [167.52103, -46.41337], [169.70504, -47.56021]]]]
22089           }
22090         }, {
22091           type: "Feature",
22092           properties: {
22093             wikidata: "Q123076",
22094             nameEn: "Palmyra Atoll",
22095             aliases: ["UM-95"],
22096             country: "US",
22097             groups: ["UM", "Q1352230", "061", "009", "UN"],
22098             level: "subterritory",
22099             roadSpeedUnit: "mph",
22100             roadHeightUnit: "ft",
22101             callingCodes: ["1"]
22102           },
22103           geometry: {
22104             type: "MultiPolygon",
22105             coordinates: [[[[-161.06795, 5.2462], [-161.0731, 7.1291], [-163.24478, 5.24198], [-161.06795, 5.2462]]]]
22106           }
22107         }, {
22108           type: "Feature",
22109           properties: {
22110             wikidata: "Q130574",
22111             nameEn: "Chafarinas Islands",
22112             country: "ES",
22113             groups: ["EU", "Q191011", "015", "002", "UN"],
22114             level: "subterritory"
22115           },
22116           geometry: {
22117             type: "MultiPolygon",
22118             coordinates: [[[[-2.40316, 35.16893], [-2.43262, 35.20652], [-2.45965, 35.16527], [-2.40316, 35.16893]]]]
22119           }
22120         }, {
22121           type: "Feature",
22122           properties: {
22123             wikidata: "Q130895",
22124             nameEn: "Kingman Reef",
22125             aliases: ["UM-89"],
22126             country: "US",
22127             groups: ["UM", "Q1352230", "061", "009", "UN"],
22128             level: "subterritory",
22129             roadSpeedUnit: "mph",
22130             roadHeightUnit: "ft"
22131           },
22132           geometry: {
22133             type: "MultiPolygon",
22134             coordinates: [[[[-161.0731, 7.1291], [-163.16627, 7.15036], [-163.24478, 5.24198], [-161.0731, 7.1291]]]]
22135           }
22136         }, {
22137           type: "Feature",
22138           properties: {
22139             wikidata: "Q131008",
22140             nameEn: "Johnston Atoll",
22141             aliases: ["JT", "JTN", "JTUM", "396", "UM-67"],
22142             country: "US",
22143             groups: ["UM", "Q1352230", "061", "009", "UN"],
22144             level: "subterritory",
22145             roadSpeedUnit: "mph",
22146             roadHeightUnit: "ft",
22147             callingCodes: ["1"]
22148           },
22149           geometry: {
22150             type: "MultiPolygon",
22151             coordinates: [[[[-170.65691, 16.57199], [-168.87689, 16.01159], [-169.2329, 17.4933], [-170.65691, 16.57199]]]]
22152           }
22153         }, {
22154           type: "Feature",
22155           properties: {
22156             wikidata: "Q131305",
22157             nameEn: "Howland Island",
22158             aliases: ["UM-84"],
22159             country: "US",
22160             groups: ["UM", "Q1352230", "061", "009", "UN"],
22161             level: "subterritory",
22162             roadSpeedUnit: "mph",
22163             roadHeightUnit: "ft"
22164           },
22165           geometry: {
22166             type: "MultiPolygon",
22167             coordinates: [[[[-177.91421, 0.39582], [-175.31323, 0.5442], [-176.74464, 2.28109], [-177.91421, 0.39582]]]]
22168           }
22169         }, {
22170           type: "Feature",
22171           properties: {
22172             wikidata: "Q133888",
22173             nameEn: "Ashmore and Cartier Islands",
22174             country: "AU",
22175             groups: ["053", "009", "UN"],
22176             driveSide: "left",
22177             callingCodes: ["61"]
22178           },
22179           geometry: {
22180             type: "MultiPolygon",
22181             coordinates: [[[[123.7463, -11.1783], [120.6877, -13.59408], [125.29076, -12.33139], [123.7463, -11.1783]]]]
22182           }
22183         }, {
22184           type: "Feature",
22185           properties: {
22186             wikidata: "Q153732",
22187             nameEn: "Mariana Islands",
22188             level: "sharedLandform"
22189           },
22190           geometry: null
22191         }, {
22192           type: "Feature",
22193           properties: {
22194             wikidata: "Q172216",
22195             nameEn: "Coral Sea Islands",
22196             country: "AU",
22197             groups: ["053", "009", "UN"],
22198             driveSide: "left",
22199             callingCodes: ["61"]
22200           },
22201           geometry: {
22202             type: "MultiPolygon",
22203             coordinates: [[[[159.77159, -28.41151], [156.73836, -14.50464], [145.2855, -9.62524], [147.69992, -17.5933], [152.93188, -20.92631], [154.02855, -24.43238], [159.77159, -28.41151]]]]
22204           }
22205         }, {
22206           type: "Feature",
22207           properties: {
22208             wikidata: "Q179313",
22209             nameEn: "Alderney",
22210             country: "GB",
22211             groups: ["GG", "830", "Q185086", "154", "150", "UN"],
22212             level: "subterritory",
22213             driveSide: "left",
22214             roadSpeedUnit: "mph",
22215             roadHeightUnit: "ft",
22216             callingCodes: ["44 01481"]
22217           },
22218           geometry: {
22219             type: "MultiPolygon",
22220             coordinates: [[[[-2.36485, 49.48223], [-2.09454, 49.46288], [-2.02963, 49.91866], [-2.49556, 49.79012], [-2.36485, 49.48223]]]]
22221           }
22222         }, {
22223           type: "Feature",
22224           properties: {
22225             wikidata: "Q185086",
22226             nameEn: "Crown Dependencies",
22227             country: "GB",
22228             level: "subcountryGroup"
22229           },
22230           geometry: null
22231         }, {
22232           type: "Feature",
22233           properties: {
22234             wikidata: "Q190571",
22235             nameEn: "Scattered Islands",
22236             country: "FR",
22237             groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
22238             level: "subterritory"
22239           },
22240           geometry: {
22241             type: "MultiPolygon",
22242             coordinates: [[[[53.53458, -16.36909], [54.96649, -16.28353], [54.61476, -15.02273], [53.53458, -16.36909]]], [[[38.55969, -20.75596], [40.68027, -23.38889], [43.52893, -15.62903], [38.55969, -20.75596]]], [[[47.03092, -11.05648], [47.11593, -12.08552], [47.96702, -11.46447], [47.03092, -11.05648]]]]
22243           }
22244         }, {
22245           type: "Feature",
22246           properties: {
22247             wikidata: "Q191011",
22248             nameEn: "Plazas de soberan\xEDa",
22249             country: "ES"
22250           },
22251           geometry: null
22252         }, {
22253           type: "Feature",
22254           properties: {
22255             wikidata: "Q191146",
22256             nameEn: "Pe\xF1\xF3n de V\xE9lez de la Gomera",
22257             country: "ES",
22258             groups: ["EU", "Q191011", "015", "002", "UN"],
22259             level: "subterritory"
22260           },
22261           geometry: {
22262             type: "MultiPolygon",
22263             coordinates: [[[[-4.30191, 35.17419], [-4.30112, 35.17058], [-4.29436, 35.17149], [-4.30191, 35.17419]]]]
22264           }
22265         }, {
22266           type: "Feature",
22267           properties: {
22268             wikidata: "Q201698",
22269             nameEn: "Crozet Islands",
22270             country: "FR",
22271             groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
22272             level: "subterritory"
22273           },
22274           geometry: {
22275             type: "MultiPolygon",
22276             coordinates: [[[[55.03425, -43.65017], [46.31615, -46.28749], [54.5587, -47.93013], [55.03425, -43.65017]]]]
22277           }
22278         }, {
22279           type: "Feature",
22280           properties: {
22281             wikidata: "Q578170",
22282             nameEn: "Contiguous United States",
22283             aliases: ["CONUS"],
22284             country: "US",
22285             groups: ["Q35657", "021", "003", "019", "UN"],
22286             roadSpeedUnit: "mph",
22287             roadHeightUnit: "ft",
22288             callingCodes: ["1"]
22289           },
22290           geometry: {
22291             type: "MultiPolygon",
22292             coordinates: [[[[-97.13927, 25.96583], [-96.92418, 25.97377], [-80.57035, 24.0565], [-78.91214, 27.76553], [-61.98255, 37.34815], [-67.16117, 44.20069], [-66.93432, 44.82597], [-66.96824, 44.83078], [-66.98249, 44.87071], [-66.96824, 44.90965], [-67.0216, 44.95333], [-67.11316, 45.11176], [-67.15965, 45.16179], [-67.19603, 45.16771], [-67.20349, 45.1722], [-67.22751, 45.16344], [-67.27039, 45.1934], [-67.29748, 45.18173], [-67.29754, 45.14865], [-67.34927, 45.122], [-67.48201, 45.27351], [-67.42394, 45.37969], [-67.50578, 45.48971], [-67.42144, 45.50584], [-67.43815, 45.59162], [-67.6049, 45.60725], [-67.80705, 45.69528], [-67.80653, 45.80022], [-67.75654, 45.82324], [-67.80961, 45.87531], [-67.75196, 45.91814], [-67.78111, 45.9392], [-67.78578, 47.06473], [-67.87993, 47.10377], [-67.94843, 47.1925], [-68.23244, 47.35712], [-68.37458, 47.35851], [-68.38332, 47.28723], [-68.57914, 47.28431], [-68.60575, 47.24659], [-68.70125, 47.24399], [-68.89222, 47.1807], [-69.05039, 47.2456], [-69.05073, 47.30076], [-69.05148, 47.42012], [-69.22119, 47.46461], [-69.99966, 46.69543], [-70.05812, 46.41768], [-70.18547, 46.35357], [-70.29078, 46.18832], [-70.23855, 46.1453], [-70.31025, 45.96424], [-70.24694, 45.95138], [-70.25976, 45.89675], [-70.41523, 45.79497], [-70.38934, 45.73215], [-70.54019, 45.67291], [-70.68516, 45.56964], [-70.72651, 45.49771], [-70.62518, 45.42286], [-70.65383, 45.37592], [-70.78372, 45.43269], [-70.82638, 45.39828], [-70.80236, 45.37444], [-70.84816, 45.22698], [-70.89864, 45.2398], [-70.91169, 45.29849], [-70.95193, 45.33895], [-71.0107, 45.34819], [-71.01866, 45.31573], [-71.08364, 45.30623], [-71.14568, 45.24128], [-71.19723, 45.25438], [-71.22338, 45.25184], [-71.29371, 45.29996], [-71.37133, 45.24624], [-71.44252, 45.2361], [-71.40364, 45.21382], [-71.42778, 45.12624], [-71.48735, 45.07784], [-71.50067, 45.01357], [-73.35025, 45.00942], [-74.32699, 44.99029], [-74.66689, 45.00646], [-74.8447, 45.00606], [-74.99101, 44.98051], [-75.01363, 44.95608], [-75.2193, 44.87821], [-75.41441, 44.76614], [-75.76813, 44.51537], [-75.8217, 44.43176], [-75.95947, 44.34463], [-76.00018, 44.34896], [-76.16285, 44.28262], [-76.1664, 44.23051], [-76.244, 44.19643], [-76.31222, 44.19894], [-76.35324, 44.13493], [-76.43859, 44.09393], [-76.79706, 43.63099], [-79.25796, 43.54052], [-79.06921, 43.26183], [-79.05512, 43.25375], [-79.05544, 43.21224], [-79.05002, 43.20133], [-79.05384, 43.17418], [-79.04652, 43.16396], [-79.0427, 43.13934], [-79.06881, 43.12029], [-79.05671, 43.10937], [-79.07486, 43.07845], [-79.01055, 43.06659], [-78.99941, 43.05612], [-79.02424, 43.01983], [-79.02074, 42.98444], [-78.98126, 42.97], [-78.96312, 42.95509], [-78.93224, 42.95229], [-78.90905, 42.93022], [-78.90712, 42.89733], [-78.93684, 42.82887], [-82.67862, 41.67615], [-83.11184, 41.95671], [-83.14962, 42.04089], [-83.12724, 42.2376], [-83.09837, 42.28877], [-83.07837, 42.30978], [-83.02253, 42.33045], [-82.82964, 42.37355], [-82.64242, 42.55594], [-82.58873, 42.54984], [-82.57583, 42.5718], [-82.51858, 42.611], [-82.51063, 42.66025], [-82.46613, 42.76615], [-82.4826, 42.8068], [-82.45331, 42.93139], [-82.4253, 42.95423], [-82.4146, 42.97626], [-82.42469, 42.992], [-82.48419, 45.30225], [-83.59589, 45.82131], [-83.43746, 45.99749], [-83.57017, 46.105], [-83.83329, 46.12169], [-83.90453, 46.05922], [-83.95399, 46.05634], [-84.1096, 46.23987], [-84.09756, 46.25512], [-84.11615, 46.2681], [-84.11254, 46.32329], [-84.13451, 46.39218], [-84.11196, 46.50248], [-84.12885, 46.53068], [-84.17723, 46.52753], [-84.1945, 46.54061], [-84.2264, 46.53337], [-84.26351, 46.49508], [-84.29893, 46.49127], [-84.34174, 46.50683], [-84.42101, 46.49853], [-84.4481, 46.48972], [-84.47607, 46.45225], [-84.55635, 46.45974], [-84.85871, 46.88881], [-88.37033, 48.30586], [-89.48837, 48.01412], [-89.57972, 48.00023], [-89.77248, 48.02607], [-89.89974, 47.98109], [-90.07418, 48.11043], [-90.56312, 48.09488], [-90.56444, 48.12184], [-90.75045, 48.09143], [-90.87588, 48.2484], [-91.08016, 48.18096], [-91.25025, 48.08522], [-91.43248, 48.04912], [-91.45829, 48.07454], [-91.58025, 48.04339], [-91.55649, 48.10611], [-91.70451, 48.11805], [-91.71231, 48.19875], [-91.86125, 48.21278], [-91.98929, 48.25409], [-92.05339, 48.35958], [-92.14732, 48.36578], [-92.202, 48.35252], [-92.26662, 48.35651], [-92.30939, 48.31251], [-92.27167, 48.25046], [-92.37185, 48.22259], [-92.48147, 48.36609], [-92.45588, 48.40624], [-92.50712, 48.44921], [-92.65606, 48.43471], [-92.71323, 48.46081], [-92.69927, 48.49573], [-92.62747, 48.50278], [-92.6342, 48.54133], [-92.7287, 48.54005], [-92.94973, 48.60866], [-93.25391, 48.64266], [-93.33946, 48.62787], [-93.3712, 48.60599], [-93.39758, 48.60364], [-93.40693, 48.60948], [-93.44472, 48.59147], [-93.47022, 48.54357], [-93.66382, 48.51845], [-93.79267, 48.51631], [-93.80939, 48.52439], [-93.80676, 48.58232], [-93.83288, 48.62745], [-93.85769, 48.63284], [-94.23215, 48.65202], [-94.25104, 48.65729], [-94.25172, 48.68404], [-94.27153, 48.70232], [-94.4174, 48.71049], [-94.44258, 48.69223], [-94.53826, 48.70216], [-94.54885, 48.71543], [-94.58903, 48.71803], [-94.69335, 48.77883], [-94.69669, 48.80918], [-94.70486, 48.82365], [-94.70087, 48.8339], [-94.687, 48.84077], [-94.75017, 49.09931], [-94.77355, 49.11998], [-94.82487, 49.29483], [-94.8159, 49.32299], [-94.85381, 49.32492], [-94.95681, 49.37035], [-94.99532, 49.36579], [-95.01419, 49.35647], [-95.05825, 49.35311], [-95.12903, 49.37056], [-95.15357, 49.384], [-95.15355, 48.9996], [-123.32163, 49.00419], [-123.0093, 48.83186], [-123.0093, 48.76586], [-123.26565, 48.6959], [-123.15614, 48.35395], [-123.50039, 48.21223], [-125.03842, 48.53282], [-133.98258, 38.06389], [-118.48109, 32.5991], [-117.1243, 32.53427], [-115.88053, 32.63624], [-114.71871, 32.71894], [-114.76736, 32.64094], [-114.80584, 32.62028], [-114.81141, 32.55543], [-114.79524, 32.55731], [-114.82011, 32.49609], [-111.07523, 31.33232], [-108.20979, 31.33316], [-108.20899, 31.78534], [-106.529, 31.784], [-106.52266, 31.77509], [-106.51251, 31.76922], [-106.50962, 31.76155], [-106.50111, 31.75714], [-106.48815, 31.74769], [-106.47298, 31.75054], [-106.46726, 31.75998], [-106.45244, 31.76523], [-106.43419, 31.75478], [-106.41773, 31.75196], [-106.38003, 31.73151], [-106.3718, 31.71165], [-106.34864, 31.69663], [-106.33419, 31.66303], [-106.30305, 31.62154], [-106.28084, 31.56173], [-106.24612, 31.54193], [-106.23711, 31.51262], [-106.20346, 31.46305], [-106.09025, 31.40569], [-106.00363, 31.39181], [-104.77674, 30.4236], [-104.5171, 29.64671], [-104.3969, 29.57105], [-104.39363, 29.55396], [-104.37752, 29.54255], [-103.15787, 28.93865], [-102.60596, 29.8192], [-101.47277, 29.7744], [-101.05686, 29.44738], [-101.01128, 29.36947], [-100.96725, 29.3477], [-100.94579, 29.34523], [-100.94056, 29.33371], [-100.87982, 29.296], [-100.79696, 29.24688], [-100.67294, 29.09744], [-100.63689, 28.90812], [-100.59809, 28.88197], [-100.52313, 28.75598], [-100.5075, 28.74066], [-100.51222, 28.70679], [-100.50029, 28.66117], [-99.55409, 27.61314], [-99.51478, 27.55836], [-99.52955, 27.49747], [-99.50208, 27.50021], [-99.48045, 27.49016], [-99.482, 27.47128], [-99.49744, 27.43746], [-99.53573, 27.30926], [-99.08477, 26.39849], [-99.03053, 26.41249], [-99.00546, 26.3925], [-98.35126, 26.15129], [-98.30491, 26.10475], [-98.27075, 26.09457], [-98.24603, 26.07191], [-97.97017, 26.05232], [-97.95155, 26.0625], [-97.66511, 26.01708], [-97.52025, 25.88518], [-97.49828, 25.89877], [-97.45669, 25.86874], [-97.42511, 25.83969], [-97.37332, 25.83854], [-97.35946, 25.92189], [-97.13927, 25.96583]]]]
22293           }
22294         }, {
22295           type: "Feature",
22296           properties: {
22297             wikidata: "Q620634",
22298             nameEn: "Bir Tawil",
22299             groups: ["015", "002"],
22300             level: "territory"
22301           },
22302           geometry: {
22303             type: "MultiPolygon",
22304             coordinates: [[[[33.17563, 22.00405], [33.57251, 21.72406], [33.99686, 21.76784], [34.0765, 22.00501], [33.17563, 22.00405]]]]
22305           }
22306         }, {
22307           type: "Feature",
22308           properties: {
22309             wikidata: "Q639185",
22310             nameEn: "Peros Banhos",
22311             country: "GB",
22312             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
22313             level: "subterritory"
22314           },
22315           geometry: {
22316             type: "MultiPolygon",
22317             coordinates: [[[[72.12587, -4.02588], [70.1848, -6.37445], [72.09518, -5.61768], [72.12587, -4.02588]]]]
22318           }
22319         }, {
22320           type: "Feature",
22321           properties: {
22322             wikidata: "Q644636",
22323             nameEn: "Cyprus",
22324             level: "sharedLandform"
22325           },
22326           geometry: null
22327         }, {
22328           type: "Feature",
22329           properties: {
22330             wikidata: "Q851132",
22331             nameEn: "New Zealand Outlying Islands",
22332             country: "NZ",
22333             level: "subcountryGroup"
22334           },
22335           geometry: null
22336         }, {
22337           type: "Feature",
22338           properties: {
22339             wikidata: "Q875134",
22340             nameEn: "European Russia",
22341             country: "RU",
22342             groups: ["151", "150", "UN"],
22343             callingCodes: ["7"]
22344           },
22345           geometry: {
22346             type: "MultiPolygon",
22347             coordinates: [[[[18.57853, 55.25302], [19.64312, 54.45423], [19.8038, 54.44203], [20.63871, 54.3706], [21.41123, 54.32395], [22.79705, 54.36264], [22.7253, 54.41732], [22.70208, 54.45312], [22.67788, 54.532], [22.71293, 54.56454], [22.68021, 54.58486], [22.7522, 54.63525], [22.74225, 54.64339], [22.75467, 54.6483], [22.73397, 54.66604], [22.73631, 54.72952], [22.87317, 54.79492], [22.85083, 54.88711], [22.76422, 54.92521], [22.68723, 54.9811], [22.65451, 54.97037], [22.60075, 55.01863], [22.58907, 55.07085], [22.47688, 55.04408], [22.31562, 55.0655], [22.14267, 55.05345], [22.11697, 55.02131], [22.06087, 55.02935], [22.02582, 55.05078], [22.03984, 55.07888], [21.99543, 55.08691], [21.96505, 55.07353], [21.85521, 55.09493], [21.64954, 55.1791], [21.55605, 55.20311], [21.51095, 55.18507], [21.46766, 55.21115], [21.38446, 55.29348], [21.35465, 55.28427], [21.26425, 55.24456], [20.95181, 55.27994], [20.60454, 55.40986], [18.57853, 55.25302]]], [[[26.32936, 60.00121], [26.90044, 59.63819], [27.85643, 59.58538], [28.04187, 59.47017], [28.19061, 59.39962], [28.21137, 59.38058], [28.20537, 59.36491], [28.19284, 59.35791], [28.14215, 59.28934], [28.00689, 59.28351], [27.90911, 59.24353], [27.87978, 59.18097], [27.80482, 59.1116], [27.74429, 58.98351], [27.36366, 58.78381], [27.55489, 58.39525], [27.48541, 58.22615], [27.62393, 58.09462], [27.67282, 57.92627], [27.81841, 57.89244], [27.78526, 57.83963], [27.56689, 57.83356], [27.50171, 57.78842], [27.52615, 57.72843], [27.3746, 57.66834], [27.40393, 57.62125], [27.31919, 57.57672], [27.34698, 57.52242], [27.56832, 57.53728], [27.52453, 57.42826], [27.86101, 57.29402], [27.66511, 56.83921], [27.86101, 56.88204], [28.04768, 56.59004], [28.13526, 56.57989], [28.10069, 56.524], [28.19057, 56.44637], [28.16599, 56.37806], [28.23716, 56.27588], [28.15217, 56.16964], [28.30571, 56.06035], [28.36888, 56.05805], [28.37987, 56.11399], [28.43068, 56.09407], [28.5529, 56.11705], [28.68337, 56.10173], [28.63668, 56.07262], [28.73418, 55.97131], [29.08299, 56.03427], [29.21717, 55.98971], [29.44692, 55.95978], [29.3604, 55.75862], [29.51283, 55.70294], [29.61446, 55.77716], [29.80672, 55.79569], [29.97975, 55.87281], [30.12136, 55.8358], [30.27776, 55.86819], [30.30987, 55.83592], [30.48257, 55.81066], [30.51346, 55.78982], [30.51037, 55.76568], [30.63344, 55.73079], [30.67464, 55.64176], [30.72957, 55.66268], [30.7845, 55.58514], [30.86003, 55.63169], [30.93419, 55.6185], [30.95204, 55.50667], [30.90123, 55.46621], [30.93144, 55.3914], [30.8257, 55.3313], [30.81946, 55.27931], [30.87944, 55.28223], [30.97369, 55.17134], [31.02071, 55.06167], [31.00972, 55.02783], [30.94243, 55.03964], [30.9081, 55.02232], [30.95754, 54.98609], [30.93144, 54.9585], [30.81759, 54.94064], [30.8264, 54.90062], [30.75165, 54.80699], [30.95479, 54.74346], [30.97127, 54.71967], [31.0262, 54.70698], [30.98226, 54.68872], [30.99187, 54.67046], [31.19339, 54.66947], [31.21399, 54.63113], [31.08543, 54.50361], [31.22945, 54.46585], [31.3177, 54.34067], [31.30791, 54.25315], [31.57002, 54.14535], [31.89599, 54.0837], [31.88744, 54.03653], [31.85019, 53.91801], [31.77028, 53.80015], [31.89137, 53.78099], [32.12621, 53.81586], [32.36663, 53.7166], [32.45717, 53.74039], [32.50112, 53.68594], [32.40499, 53.6656], [32.47777, 53.5548], [32.74968, 53.45597], [32.73257, 53.33494], [32.51725, 53.28431], [32.40773, 53.18856], [32.15368, 53.07594], [31.82373, 53.10042], [31.787, 53.18033], [31.62496, 53.22886], [31.56316, 53.19432], [31.40523, 53.21406], [31.36403, 53.13504], [31.3915, 53.09712], [31.33519, 53.08805], [31.32283, 53.04101], [31.24147, 53.031], [31.35667, 52.97854], [31.592, 52.79011], [31.57277, 52.71613], [31.50406, 52.69707], [31.63869, 52.55361], [31.56316, 52.51518], [31.61397, 52.48843], [31.62084, 52.33849], [31.57971, 52.32146], [31.70735, 52.26711], [31.6895, 52.1973], [31.77877, 52.18636], [31.7822, 52.11406], [31.81722, 52.09955], [31.85018, 52.11305], [31.96141, 52.08015], [31.92159, 52.05144], [32.08813, 52.03319], [32.23331, 52.08085], [32.2777, 52.10266], [32.34044, 52.1434], [32.33083, 52.23685], [32.38988, 52.24946], [32.3528, 52.32842], [32.54781, 52.32423], [32.69475, 52.25535], [32.85405, 52.27888], [32.89937, 52.2461], [33.18913, 52.3754], [33.51323, 52.35779], [33.48027, 52.31499], [33.55718, 52.30324], [33.78789, 52.37204], [34.05239, 52.20132], [34.11199, 52.14087], [34.09413, 52.00835], [34.41136, 51.82793], [34.42922, 51.72852], [34.07765, 51.67065], [34.17599, 51.63253], [34.30562, 51.5205], [34.22048, 51.4187], [34.33446, 51.363], [34.23009, 51.26429], [34.31661, 51.23936], [34.38802, 51.2746], [34.6613, 51.25053], [34.6874, 51.18], [34.82472, 51.17483], [34.97304, 51.2342], [35.14058, 51.23162], [35.12685, 51.16191], [35.20375, 51.04723], [35.31774, 51.08434], [35.40837, 51.04119], [35.32598, 50.94524], [35.39307, 50.92145], [35.41367, 50.80227], [35.47704, 50.77274], [35.48116, 50.66405], [35.39464, 50.64751], [35.47463, 50.49247], [35.58003, 50.45117], [35.61711, 50.35707], [35.73659, 50.35489], [35.80388, 50.41356], [35.8926, 50.43829], [36.06893, 50.45205], [36.20763, 50.3943], [36.30101, 50.29088], [36.47817, 50.31457], [36.58371, 50.28563], [36.56655, 50.2413], [36.64571, 50.218], [36.69377, 50.26982], [36.91762, 50.34963], [37.08468, 50.34935], [37.48204, 50.46079], [37.47243, 50.36277], [37.62486, 50.29966], [37.62879, 50.24481], [37.61113, 50.21976], [37.75807, 50.07896], [37.79515, 50.08425], [37.90776, 50.04194], [38.02999, 49.94482], [38.02999, 49.90592], [38.21675, 49.98104], [38.18517, 50.08161], [38.32524, 50.08866], [38.35408, 50.00664], [38.65688, 49.97176], [38.68677, 50.00904], [38.73311, 49.90238], [38.90477, 49.86787], [38.9391, 49.79524], [39.1808, 49.88911], [39.27968, 49.75976], [39.44496, 49.76067], [39.59142, 49.73758], [39.65047, 49.61761], [39.84548, 49.56064], [40.13249, 49.61672], [40.16683, 49.56865], [40.03636, 49.52321], [40.03087, 49.45452], [40.1141, 49.38798], [40.14912, 49.37681], [40.18331, 49.34996], [40.22176, 49.25683], [40.01988, 49.1761], [39.93437, 49.05709], [39.6836, 49.05121], [39.6683, 48.99454], [39.71353, 48.98959], [39.72649, 48.9754], [39.74874, 48.98675], [39.78368, 48.91596], [39.98967, 48.86901], [40.03636, 48.91957], [40.08168, 48.87443], [39.97182, 48.79398], [39.79466, 48.83739], [39.73104, 48.7325], [39.71765, 48.68673], [39.67226, 48.59368], [39.79764, 48.58668], [39.84548, 48.57821], [39.86196, 48.46633], [39.88794, 48.44226], [39.94847, 48.35055], [39.84136, 48.33321], [39.84273, 48.30947], [39.90041, 48.3049], [39.91465, 48.26743], [39.95248, 48.29972], [39.9693, 48.29904], [39.97325, 48.31399], [39.99241, 48.31768], [40.00752, 48.22445], [39.94847, 48.22811], [39.83724, 48.06501], [39.88256, 48.04482], [39.77544, 48.04206], [39.82213, 47.96396], [39.73935, 47.82876], [38.87979, 47.87719], [38.79628, 47.81109], [38.76379, 47.69346], [38.35062, 47.61631], [38.28679, 47.53552], [38.28954, 47.39255], [38.22225, 47.30788], [38.33074, 47.30508], [38.32112, 47.2585], [38.23049, 47.2324], [38.22955, 47.12069], [38.3384, 46.98085], [38.12112, 46.86078], [37.62608, 46.82615], [35.23066, 45.79231], [35.04991, 45.76827], [36.6645, 45.4514], [36.6545, 45.3417], [36.5049, 45.3136], [36.475, 45.2411], [36.4883, 45.0488], [33.5943, 44.03313], [39.81147, 43.06294], [40.0078, 43.38551], [40.00853, 43.40578], [40.01552, 43.42025], [40.01007, 43.42411], [40.03312, 43.44262], [40.04445, 43.47776], [40.10657, 43.57344], [40.65957, 43.56212], [41.64935, 43.22331], [42.40563, 43.23226], [42.66667, 43.13917], [42.75889, 43.19651], [43.03322, 43.08883], [43.0419, 43.02413], [43.81453, 42.74297], [43.73119, 42.62043], [43.95517, 42.55396], [44.54202, 42.75699], [44.70002, 42.74679], [44.80941, 42.61277], [44.88754, 42.74934], [45.15318, 42.70598], [45.36501, 42.55268], [45.78692, 42.48358], [45.61676, 42.20768], [46.42738, 41.91323], [46.5332, 41.87389], [46.58924, 41.80547], [46.75269, 41.8623], [46.8134, 41.76252], [47.00955, 41.63583], [46.99554, 41.59743], [47.03757, 41.55434], [47.10762, 41.59044], [47.34579, 41.27884], [47.49004, 41.26366], [47.54504, 41.20275], [47.62288, 41.22969], [47.75831, 41.19455], [47.87973, 41.21798], [48.07587, 41.49957], [48.22064, 41.51472], [48.2878, 41.56221], [48.40277, 41.60441], [48.42301, 41.65444], [48.55078, 41.77917], [48.5867, 41.84306], [48.80971, 41.95365], [49.2134, 44.84989], [49.88945, 46.04554], [49.32259, 46.26944], [49.16518, 46.38542], [48.54988, 46.56267], [48.51142, 46.69268], [49.01136, 46.72716], [48.52326, 47.4102], [48.45173, 47.40818], [48.15348, 47.74545], [47.64973, 47.76559], [47.41689, 47.83687], [47.38731, 47.68176], [47.12107, 47.83687], [47.11516, 48.27188], [46.49011, 48.43019], [46.78392, 48.95352], [47.00857, 49.04921], [47.04658, 49.19834], [46.78398, 49.34026], [46.9078, 49.86707], [47.18319, 49.93721], [47.34589, 50.09308], [47.30448, 50.30894], [47.58551, 50.47867], [48.10044, 50.09242], [48.24519, 49.86099], [48.42564, 49.82283], [48.68352, 49.89546], [48.90782, 50.02281], [48.57946, 50.63278], [48.86936, 50.61589], [49.12673, 50.78639], [49.41959, 50.85927], [49.39001, 51.09396], [49.76866, 51.11067], [49.97277, 51.2405], [50.26859, 51.28677], [50.59695, 51.61859], [51.26254, 51.68466], [51.301, 51.48799], [51.77431, 51.49536], [51.8246, 51.67916], [52.36119, 51.74161], [52.54329, 51.48444], [53.46165, 51.49445], [53.69299, 51.23466], [54.12248, 51.11542], [54.46331, 50.85554], [54.41894, 50.61214], [54.55797, 50.52006], [54.71476, 50.61214], [54.56685, 51.01958], [54.72067, 51.03261], [55.67774, 50.54508], [56.11398, 50.7471], [56.17906, 50.93204], [57.17302, 51.11253], [57.44221, 50.88354], [57.74986, 50.93017], [57.75578, 51.13852], [58.3208, 51.15151], [58.87974, 50.70852], [59.48928, 50.64216], [59.51886, 50.49937], [59.81172, 50.54451], [60.01288, 50.8163], [60.17262, 50.83312], [60.31914, 50.67705], [60.81833, 50.6629], [61.4431, 50.80679], [61.56889, 51.23679], [61.6813, 51.25716], [61.55114, 51.32746], [61.50677, 51.40687], [60.95655, 51.48615], [60.92401, 51.61124], [60.5424, 51.61675], [60.36787, 51.66815], [60.50986, 51.7964], [60.09867, 51.87135], [59.99809, 51.98263], [59.91279, 52.06924], [60.17253, 52.25814], [60.17516, 52.39457], [59.25033, 52.46803], [59.22409, 52.28437], [58.79644, 52.43392], [58.94336, 53.953], [59.70487, 54.14846], [59.95217, 54.85853], [57.95234, 54.39672], [57.14829, 54.84204], [57.25137, 55.26262], [58.81825, 55.03378], [59.49035, 55.60486], [59.28419, 56.15739], [57.51527, 56.08729], [57.28024, 56.87898], [58.07604, 57.08308], [58.13789, 57.68097], [58.81412, 57.71602], [58.71104, 58.07475], [59.40376, 58.45822], [59.15636, 59.14682], [58.3853, 59.487], [59.50685, 60.91162], [59.36223, 61.3882], [59.61398, 62.44915], [59.24834, 63.01859], [59.80579, 64.13948], [59.63945, 64.78384], [60.74386, 64.95767], [61.98014, 65.72191], [66.1708, 67.61252], [64.18965, 69.94255], [76.13964, 83.37843], [36.85549, 84.09565], [32.07813, 72.01005], [31.59909, 70.16571], [30.84095, 69.80584], [30.95011, 69.54699], [30.52662, 69.54699], [30.16363, 69.65244], [29.97205, 69.41623], [29.27631, 69.2811], [29.26623, 69.13794], [29.0444, 69.0119], [28.91738, 69.04774], [28.45957, 68.91417], [28.78224, 68.86696], [28.43941, 68.53366], [28.62982, 68.19816], [29.34179, 68.06655], [29.66955, 67.79872], [30.02041, 67.67523], [29.91155, 67.51507], [28.9839, 66.94139], [29.91155, 66.13863], [30.16363, 65.66935], [29.97205, 65.70256], [29.74013, 65.64025], [29.84096, 65.56945], [29.68972, 65.31803], [29.61914, 65.23791], [29.8813, 65.22101], [29.84096, 65.1109], [29.61914, 65.05993], [29.68972, 64.80789], [30.05271, 64.79072], [30.12329, 64.64862], [30.01238, 64.57513], [30.06279, 64.35782], [30.4762, 64.25728], [30.55687, 64.09036], [30.25437, 63.83364], [29.98213, 63.75795], [30.49637, 63.46666], [31.23244, 63.22239], [31.29294, 63.09035], [31.58535, 62.91642], [31.38369, 62.66284], [31.10136, 62.43042], [29.01829, 61.17448], [28.82816, 61.1233], [28.47974, 60.93365], [27.77352, 60.52722], [27.71177, 60.3893], [27.44953, 60.22766], [26.32936, 60.00121]]]]
22348           }
22349         }, {
22350           type: "Feature",
22351           properties: {
22352             wikidata: "Q1083368",
22353             nameEn: "Mainland Finland",
22354             country: "FI",
22355             groups: ["EU", "154", "150", "UN"],
22356             callingCodes: ["358"]
22357           },
22358           geometry: {
22359             type: "MultiPolygon",
22360             coordinates: [[[[29.12697, 69.69193], [28.36883, 69.81658], [28.32849, 69.88605], [27.97558, 69.99671], [27.95542, 70.0965], [27.57226, 70.06215], [27.05802, 69.92069], [26.64461, 69.96565], [26.40261, 69.91377], [25.96904, 69.68397], [25.69679, 69.27039], [25.75729, 68.99383], [25.61613, 68.89602], [25.42455, 68.90328], [25.12206, 68.78684], [25.10189, 68.63307], [24.93048, 68.61102], [24.90023, 68.55579], [24.74898, 68.65143], [24.18432, 68.73936], [24.02299, 68.81601], [23.781, 68.84514], [23.68017, 68.70276], [23.13064, 68.64684], [22.53321, 68.74393], [22.38367, 68.71561], [22.27276, 68.89514], [21.63833, 69.27485], [21.27827, 69.31281], [21.00732, 69.22755], [20.98641, 69.18809], [21.11099, 69.10291], [21.05775, 69.0356], [20.72171, 69.11874], [20.55258, 69.06069], [20.78802, 69.03087], [20.91658, 68.96764], [20.85104, 68.93142], [20.90649, 68.89696], [21.03001, 68.88969], [22.00429, 68.50692], [22.73028, 68.40881], [23.10336, 68.26551], [23.15377, 68.14759], [23.26469, 68.15134], [23.40081, 68.05545], [23.65793, 67.9497], [23.45627, 67.85297], [23.54701, 67.59306], [23.39577, 67.46974], [23.75372, 67.43688], [23.75372, 67.29914], [23.54701, 67.25435], [23.58735, 67.20752], [23.56214, 67.17038], [23.98563, 66.84149], [23.98059, 66.79585], [23.89488, 66.772], [23.85959, 66.56434], [23.63776, 66.43568], [23.67591, 66.3862], [23.64982, 66.30603], [23.71339, 66.21299], [23.90497, 66.15802], [24.15791, 65.85385], [24.14798, 65.83466], [24.15107, 65.81427], [24.14112, 65.39731], [20.15877, 63.06556], [19.23413, 60.61414], [20.96741, 60.71528], [21.15143, 60.54555], [21.08159, 60.20167], [21.02509, 60.12142], [21.35468, 59.67511], [20.5104, 59.15546], [26.32936, 60.00121], [27.44953, 60.22766], [27.71177, 60.3893], [27.77352, 60.52722], [28.47974, 60.93365], [28.82816, 61.1233], [29.01829, 61.17448], [31.10136, 62.43042], [31.38369, 62.66284], [31.58535, 62.91642], [31.29294, 63.09035], [31.23244, 63.22239], [30.49637, 63.46666], [29.98213, 63.75795], [30.25437, 63.83364], [30.55687, 64.09036], [30.4762, 64.25728], [30.06279, 64.35782], [30.01238, 64.57513], [30.12329, 64.64862], [30.05271, 64.79072], [29.68972, 64.80789], [29.61914, 65.05993], [29.84096, 65.1109], [29.8813, 65.22101], [29.61914, 65.23791], [29.68972, 65.31803], [29.84096, 65.56945], [29.74013, 65.64025], [29.97205, 65.70256], [30.16363, 65.66935], [29.91155, 66.13863], [28.9839, 66.94139], [29.91155, 67.51507], [30.02041, 67.67523], [29.66955, 67.79872], [29.34179, 68.06655], [28.62982, 68.19816], [28.43941, 68.53366], [28.78224, 68.86696], [28.45957, 68.91417], [28.91738, 69.04774], [28.81248, 69.11997], [28.8629, 69.22395], [29.31664, 69.47994], [29.12697, 69.69193]]]]
22361           }
22362         }, {
22363           type: "Feature",
22364           properties: {
22365             wikidata: "Q1184963",
22366             nameEn: "Alhucemas Islands",
22367             country: "ES",
22368             groups: ["EU", "Q191011", "015", "002", "UN"],
22369             level: "subterritory"
22370           },
22371           geometry: {
22372             type: "MultiPolygon",
22373             coordinates: [[[[-3.90602, 35.21494], [-3.88372, 35.20767], [-3.89343, 35.22728], [-3.90602, 35.21494]]]]
22374           }
22375         }, {
22376           type: "Feature",
22377           properties: {
22378             wikidata: "Q1298289",
22379             nameEn: "Egmont Islands",
22380             country: "GB",
22381             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
22382             level: "subterritory"
22383           },
22384           geometry: {
22385             type: "MultiPolygon",
22386             coordinates: [[[[70.1848, -6.37445], [70.67958, -8.2663], [72.17991, -6.68509], [70.1848, -6.37445]]]]
22387           }
22388         }, {
22389           type: "Feature",
22390           properties: {
22391             wikidata: "Q1352230",
22392             nameEn: "US Territories",
22393             country: "US",
22394             level: "subcountryGroup"
22395           },
22396           geometry: null
22397         }, {
22398           type: "Feature",
22399           properties: {
22400             wikidata: "Q1451600",
22401             nameEn: "Overseas Countries and Territories of the EU",
22402             aliases: ["OCT"],
22403             level: "subunion"
22404           },
22405           geometry: null
22406         }, {
22407           type: "Feature",
22408           properties: {
22409             wikidata: "Q1544253",
22410             nameEn: "Great Chagos Bank",
22411             country: "GB",
22412             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
22413             level: "subterritory"
22414           },
22415           geometry: {
22416             type: "MultiPolygon",
22417             coordinates: [[[[70.1848, -6.37445], [72.17991, -6.68509], [73.20573, -5.20727], [70.1848, -6.37445]]]]
22418           }
22419         }, {
22420           type: "Feature",
22421           properties: {
22422             wikidata: "Q1585511",
22423             nameEn: "Salomon Atoll",
22424             country: "GB",
22425             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
22426             level: "subterritory"
22427           },
22428           geometry: {
22429             type: "MultiPolygon",
22430             coordinates: [[[[72.09518, -5.61768], [73.20573, -5.20727], [72.12587, -4.02588], [72.09518, -5.61768]]]]
22431           }
22432         }, {
22433           type: "Feature",
22434           properties: {
22435             wikidata: "Q1681727",
22436             nameEn: "Saint-Paul and Amsterdam",
22437             country: "FR",
22438             groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
22439             level: "subterritory"
22440           },
22441           geometry: {
22442             type: "MultiPolygon",
22443             coordinates: [[[[76.31747, -42.16264], [80.15867, -36.04977], [71.22311, -38.75287], [76.31747, -42.16264]]]]
22444           }
22445         }, {
22446           type: "Feature",
22447           properties: {
22448             wikidata: "Q1901211",
22449             nameEn: "East Malaysia",
22450             country: "MY",
22451             groups: ["Q36117", "035", "142", "UN"],
22452             driveSide: "left",
22453             callingCodes: ["60"]
22454           },
22455           geometry: {
22456             type: "MultiPolygon",
22457             coordinates: [[[[110.90339, 7.52694], [109.82788, 2.86812], [109.62558, 1.99182], [109.53794, 1.91771], [109.57923, 1.80624], [109.66397, 1.79972], [109.66397, 1.60425], [110.35354, 0.98869], [110.49182, 0.88088], [110.62374, 0.873], [111.22979, 1.08326], [111.55434, 0.97864], [111.82846, 0.99349], [111.94553, 1.12016], [112.15679, 1.17004], [112.2127, 1.44135], [112.48648, 1.56516], [113.021, 1.57819], [113.01448, 1.42832], [113.64677, 1.23933], [114.03788, 1.44787], [114.57892, 1.5], [114.80706, 1.92351], [114.80706, 2.21665], [115.1721, 2.49671], [115.11343, 2.82879], [115.53713, 3.14776], [115.58276, 3.93499], [115.90217, 4.37708], [117.25801, 4.35108], [117.47313, 4.18857], [117.67641, 4.16535], [118.06469, 4.16638], [118.93936, 4.09009], [119.52945, 5.35672], [117.98544, 6.27477], [117.93857, 6.89845], [117.17735, 7.52841], [116.79524, 7.43869], [115.02521, 5.35005], [115.16236, 5.01011], [115.15092, 4.87604], [115.20737, 4.8256], [115.27819, 4.63661], [115.2851, 4.42295], [115.36346, 4.33563], [115.31275, 4.30806], [115.09978, 4.39123], [115.07737, 4.53418], [115.04064, 4.63706], [115.02278, 4.74137], [115.02955, 4.82087], [115.05038, 4.90275], [114.99417, 4.88201], [114.96982, 4.81146], [114.88841, 4.81905], [114.8266, 4.75062], [114.77303, 4.72871], [114.83189, 4.42387], [114.88039, 4.4257], [114.78539, 4.12205], [114.64211, 4.00694], [114.49922, 4.13108], [114.4416, 4.27588], [114.32176, 4.2552], [114.32176, 4.34942], [114.26876, 4.49878], [114.15813, 4.57], [114.07448, 4.58441], [114.10166, 4.76112], [110.90339, 7.52694]]]]
22458           }
22459         }, {
22460           type: "Feature",
22461           properties: {
22462             wikidata: "Q1973345",
22463             nameEn: "Peninsular Malaysia",
22464             country: "MY",
22465             groups: ["035", "142", "UN"],
22466             driveSide: "left",
22467             callingCodes: ["60"]
22468           },
22469           geometry: {
22470             type: "MultiPolygon",
22471             coordinates: [[[[102.46318, 7.22462], [102.09086, 6.23546], [102.08127, 6.22679], [102.07732, 6.193], [102.09182, 6.14161], [102.01835, 6.05407], [101.99209, 6.04075], [101.97114, 6.01992], [101.9714, 6.00575], [101.94712, 5.98421], [101.92819, 5.85511], [101.91776, 5.84269], [101.89188, 5.8386], [101.80144, 5.74505], [101.75074, 5.79091], [101.69773, 5.75881], [101.58019, 5.93534], [101.25524, 5.78633], [101.25755, 5.71065], [101.14062, 5.61613], [100.98815, 5.79464], [101.02708, 5.91013], [101.087, 5.9193], [101.12388, 6.11411], [101.06165, 6.14161], [101.12618, 6.19431], [101.10313, 6.25617], [100.85884, 6.24929], [100.81045, 6.45086], [100.74822, 6.46231], [100.74361, 6.50811], [100.66986, 6.45086], [100.43027, 6.52389], [100.42351, 6.51762], [100.41791, 6.5189], [100.41152, 6.52299], [100.35413, 6.54932], [100.31929, 6.65413], [100.32607, 6.65933], [100.32671, 6.66526], [100.31884, 6.66423], [100.31618, 6.66781], [100.30828, 6.66462], [100.29651, 6.68439], [100.19511, 6.72559], [100.12, 6.42105], [100.0756, 6.4045], [99.91873, 6.50233], [99.50117, 6.44501], [99.31854, 5.99868], [99.75778, 3.86466], [103.03657, 1.30383], [103.56591, 1.19719], [103.62738, 1.35255], [103.67468, 1.43166], [103.7219, 1.46108], [103.74161, 1.4502], [103.76395, 1.45183], [103.81181, 1.47953], [103.86383, 1.46288], [103.89565, 1.42841], [103.93384, 1.42926], [104.00131, 1.42405], [104.02277, 1.4438], [104.04622, 1.44691], [104.07348, 1.43322], [104.08871, 1.42015], [104.09162, 1.39694], [104.08072, 1.35998], [104.12282, 1.27714], [104.34728, 1.33529], [104.56723, 1.44271], [105.01437, 3.24936], [102.46318, 7.22462]]]]
22472           }
22473         }, {
22474           type: "Feature",
22475           properties: {
22476             wikidata: "Q2093907",
22477             nameEn: "Three Kings Islands",
22478             country: "NZ",
22479             groups: ["Q851132", "053", "009", "UN"],
22480             driveSide: "left"
22481           },
22482           geometry: {
22483             type: "MultiPolygon",
22484             coordinates: [[[[174.17679, -32.62487], [170.93268, -32.97889], [171.97383, -34.64644], [174.17679, -32.62487]]]]
22485           }
22486         }, {
22487           type: "Feature",
22488           properties: {
22489             wikidata: "Q2298216",
22490             nameEn: "Solander Islands",
22491             country: "NZ",
22492             groups: ["Q851132", "053", "009", "UN"],
22493             driveSide: "left"
22494           },
22495           geometry: {
22496             type: "MultiPolygon",
22497             coordinates: [[[[167.39068, -46.49187], [166.5534, -46.39484], [166.84561, -46.84889], [167.39068, -46.49187]]]]
22498           }
22499         }, {
22500           type: "Feature",
22501           properties: {
22502             wikidata: "Q2872203",
22503             nameEn: "Mainland Australia",
22504             country: "AU",
22505             groups: ["053", "009", "UN"],
22506             level: "subcountryGroup",
22507             driveSide: "left",
22508             callingCodes: ["61"]
22509           },
22510           geometry: {
22511             type: "MultiPolygon",
22512             coordinates: [[[[88.16419, -23.49578], [123.64533, -39.13605], [159.74028, -39.1978], [159.76765, -29.76946], [154.02855, -24.43238], [152.93188, -20.92631], [147.69992, -17.5933], [145.2855, -9.62524], [143.87386, -9.02382], [143.29772, -9.33993], [142.48658, -9.36754], [142.19246, -9.15378], [141.88934, -9.36111], [141.01842, -9.35091], [135.49042, -9.2276], [127.55165, -9.05052], [125.29076, -12.33139], [88.16419, -23.49578]]]]
22513           }
22514         }, {
22515           type: "Feature",
22516           properties: {
22517             wikidata: "Q2914565",
22518             nameEn: "Autonomous Regions of Portugal",
22519             country: "PT",
22520             level: "subcountryGroup"
22521           },
22522           geometry: null
22523         }, {
22524           type: "Feature",
22525           properties: {
22526             wikidata: "Q2915956",
22527             nameEn: "Mainland Portugal",
22528             country: "PT",
22529             groups: ["Q12837", "EU", "039", "150", "UN"],
22530             level: "subcountryGroup",
22531             callingCodes: ["351"]
22532           },
22533           geometry: {
22534             type: "MultiPolygon",
22535             coordinates: [[[[-10.39881, 36.12218], [-7.37282, 36.96896], [-7.39769, 37.16868], [-7.41133, 37.20314], [-7.41854, 37.23813], [-7.43227, 37.25152], [-7.43974, 37.38913], [-7.46878, 37.47127], [-7.51759, 37.56119], [-7.41981, 37.75729], [-7.33441, 37.81193], [-7.27314, 37.90145], [-7.24544, 37.98884], [-7.12648, 38.00296], [-7.10366, 38.04404], [-7.05966, 38.01966], [-7.00375, 38.01914], [-6.93418, 38.21454], [-7.09389, 38.17227], [-7.15581, 38.27597], [-7.32529, 38.44336], [-7.265, 38.61674], [-7.26174, 38.72107], [-7.03848, 38.87221], [-7.051, 38.907], [-6.95211, 39.0243], [-6.97004, 39.07619], [-7.04011, 39.11919], [-7.10692, 39.10275], [-7.14929, 39.11287], [-7.12811, 39.17101], [-7.23566, 39.20132], [-7.23403, 39.27579], [-7.3149, 39.34857], [-7.2927, 39.45847], [-7.49477, 39.58794], [-7.54121, 39.66717], [-7.33507, 39.64569], [-7.24707, 39.66576], [-7.01613, 39.66877], [-6.97492, 39.81488], [-6.91463, 39.86618], [-6.86737, 40.01986], [-6.94233, 40.10716], [-7.00589, 40.12087], [-7.02544, 40.18564], [-7.00426, 40.23169], [-6.86085, 40.26776], [-6.86085, 40.2976], [-6.80218, 40.33239], [-6.78426, 40.36468], [-6.84618, 40.42177], [-6.84944, 40.46394], [-6.7973, 40.51723], [-6.80218, 40.55067], [-6.84292, 40.56801], [-6.79567, 40.65955], [-6.82826, 40.74603], [-6.82337, 40.84472], [-6.79892, 40.84842], [-6.80707, 40.88047], [-6.84292, 40.89771], [-6.8527, 40.93958], [-6.9357, 41.02888], [-6.913, 41.03922], [-6.88843, 41.03027], [-6.84781, 41.02692], [-6.80942, 41.03629], [-6.79241, 41.05397], [-6.75655, 41.10187], [-6.77319, 41.13049], [-6.69711, 41.1858], [-6.68286, 41.21641], [-6.65046, 41.24725], [-6.55937, 41.24417], [-6.38551, 41.35274], [-6.38553, 41.38655], [-6.3306, 41.37677], [-6.26777, 41.48796], [-6.19128, 41.57638], [-6.29863, 41.66432], [-6.44204, 41.68258], [-6.49907, 41.65823], [-6.54633, 41.68623], [-6.56426, 41.74219], [-6.51374, 41.8758], [-6.56752, 41.88429], [-6.5447, 41.94371], [-6.58544, 41.96674], [-6.61967, 41.94008], [-6.75004, 41.94129], [-6.76959, 41.98734], [-6.81196, 41.99097], [-6.82174, 41.94493], [-6.94396, 41.94403], [-6.95537, 41.96553], [-6.98144, 41.9728], [-7.01078, 41.94977], [-7.07596, 41.94977], [-7.08574, 41.97401], [-7.14115, 41.98855], [-7.18549, 41.97515], [-7.18677, 41.88793], [-7.32366, 41.8406], [-7.37092, 41.85031], [-7.42864, 41.80589], [-7.42854, 41.83262], [-7.44759, 41.84451], [-7.45566, 41.86488], [-7.49803, 41.87095], [-7.52737, 41.83939], [-7.62188, 41.83089], [-7.58603, 41.87944], [-7.65774, 41.88308], [-7.69848, 41.90977], [-7.84188, 41.88065], [-7.88055, 41.84571], [-7.88751, 41.92553], [-7.90707, 41.92432], [-7.92336, 41.8758], [-7.9804, 41.87337], [-8.01136, 41.83453], [-8.0961, 41.81024], [-8.16455, 41.81753], [-8.16944, 41.87944], [-8.19551, 41.87459], [-8.2185, 41.91237], [-8.16232, 41.9828], [-8.08796, 42.01398], [-8.08847, 42.05767], [-8.11729, 42.08537], [-8.18178, 42.06436], [-8.19406, 42.12141], [-8.18947, 42.13853], [-8.1986, 42.15402], [-8.22406, 42.1328], [-8.24681, 42.13993], [-8.2732, 42.12396], [-8.29809, 42.106], [-8.32161, 42.10218], [-8.33912, 42.08358], [-8.36353, 42.09065], [-8.38323, 42.07683], [-8.40143, 42.08052], [-8.42512, 42.07199], [-8.44123, 42.08218], [-8.48185, 42.0811], [-8.52837, 42.07658], [-8.5252, 42.06264], [-8.54563, 42.0537], [-8.58086, 42.05147], [-8.59493, 42.05708], [-8.63791, 42.04691], [-8.64626, 42.03668], [-8.65832, 42.02972], [-8.6681, 41.99703], [-8.69071, 41.98862], [-8.7478, 41.96282], [-8.74606, 41.9469], [-8.75712, 41.92833], [-8.81794, 41.90375], [-8.87157, 41.86488], [-11.19304, 41.83075], [-10.39881, 36.12218]]]]
22536           }
22537         }, {
22538           type: "Feature",
22539           properties: {
22540             wikidata: "Q3311985",
22541             nameEn: "Guernsey",
22542             country: "GB",
22543             groups: ["GG", "830", "Q185086", "154", "150", "UN"],
22544             level: "subterritory",
22545             driveSide: "left",
22546             roadSpeedUnit: "mph",
22547             roadHeightUnit: "ft",
22548             callingCodes: ["44 01481"]
22549           },
22550           geometry: {
22551             type: "MultiPolygon",
22552             coordinates: [[[[-2.49556, 49.79012], [-3.28154, 49.57329], [-2.65349, 49.15373], [-2.36485, 49.48223], [-2.49556, 49.79012]]]]
22553           }
22554         }, {
22555           type: "Feature",
22556           properties: {
22557             wikidata: "Q3320166",
22558             nameEn: "Outermost Regions of the EU",
22559             aliases: ["OMR"],
22560             level: "subunion"
22561           },
22562           geometry: null
22563         }, {
22564           type: "Feature",
22565           properties: {
22566             wikidata: "Q3336843",
22567             nameEn: "Countries of the United Kingdom",
22568             country: "GB",
22569             level: "subcountryGroup"
22570           },
22571           geometry: null
22572         }, {
22573           type: "Feature",
22574           properties: {
22575             wikidata: "Q6736667",
22576             nameEn: "Mainland India",
22577             country: "IN",
22578             groups: ["034", "142", "UN"],
22579             driveSide: "left",
22580             callingCodes: ["91"]
22581           },
22582           geometry: {
22583             type: "MultiPolygon",
22584             coordinates: [[[[89.08044, 21.41871], [89.07114, 22.15335], [88.9367, 22.58527], [88.94614, 22.66941], [88.9151, 22.75228], [88.96713, 22.83346], [88.87063, 22.95235], [88.88327, 23.03885], [88.86377, 23.08759], [88.99148, 23.21134], [88.71133, 23.2492], [88.79254, 23.46028], [88.79351, 23.50535], [88.74841, 23.47361], [88.56507, 23.64044], [88.58087, 23.87105], [88.66189, 23.87607], [88.73743, 23.91751], [88.6976, 24.14703], [88.74841, 24.1959], [88.68801, 24.31464], [88.50934, 24.32474], [88.12296, 24.51301], [88.08786, 24.63232], [88.00683, 24.66477], [88.15515, 24.85806], [88.14004, 24.93529], [88.21832, 24.96642], [88.27325, 24.88796], [88.33917, 24.86803], [88.46277, 25.07468], [88.44766, 25.20149], [88.94067, 25.18534], [89.00463, 25.26583], [89.01105, 25.30303], [88.85278, 25.34679], [88.81296, 25.51546], [88.677, 25.46959], [88.4559, 25.59227], [88.45103, 25.66245], [88.242, 25.80811], [88.13138, 25.78773], [88.08804, 25.91334], [88.16581, 26.0238], [88.1844, 26.14417], [88.34757, 26.22216], [88.35153, 26.29123], [88.51649, 26.35923], [88.48749, 26.45855], [88.36938, 26.48683], [88.35153, 26.45241], [88.33093, 26.48929], [88.41196, 26.63837], [88.4298, 26.54489], [88.62144, 26.46783], [88.69485, 26.38353], [88.67837, 26.26291], [88.78961, 26.31093], [88.85004, 26.23211], [89.05328, 26.2469], [88.91321, 26.37984], [88.92357, 26.40711], [88.95612, 26.4564], [89.08899, 26.38845], [89.15869, 26.13708], [89.35953, 26.0077], [89.53515, 26.00382], [89.57101, 25.9682], [89.63968, 26.22595], [89.70201, 26.15138], [89.73581, 26.15818], [89.77865, 26.08387], [89.77728, 26.04254], [89.86592, 25.93115], [89.80585, 25.82489], [89.84388, 25.70042], [89.86129, 25.61714], [89.81208, 25.37244], [89.84086, 25.31854], [89.83371, 25.29548], [89.87629, 25.28337], [89.90478, 25.31038], [90.1155, 25.22686], [90.40034, 25.1534], [90.65042, 25.17788], [90.87427, 25.15799], [91.25517, 25.20677], [91.63648, 25.12846], [92.0316, 25.1834], [92.33957, 25.07593], [92.39147, 25.01471], [92.49887, 24.88796], [92.38626, 24.86055], [92.25854, 24.9191], [92.15796, 24.54435], [92.11662, 24.38997], [91.96603, 24.3799], [91.89258, 24.14674], [91.82596, 24.22345], [91.76004, 24.23848], [91.73257, 24.14703], [91.65292, 24.22095], [91.63782, 24.1132], [91.55542, 24.08687], [91.37414, 24.10693], [91.35741, 23.99072], [91.29587, 24.0041], [91.22308, 23.89616], [91.25192, 23.83463], [91.15579, 23.6599], [91.28293, 23.37538], [91.36453, 23.06612], [91.40848, 23.07117], [91.4035, 23.27522], [91.46615, 23.2328], [91.54993, 23.01051], [91.61571, 22.93929], [91.7324, 23.00043], [91.81634, 23.08001], [91.76417, 23.26619], [91.84789, 23.42235], [91.95642, 23.47361], [91.95093, 23.73284], [92.04706, 23.64229], [92.15417, 23.73409], [92.26541, 23.70392], [92.38214, 23.28705], [92.37665, 22.9435], [92.5181, 22.71441], [92.60029, 22.1522], [92.56616, 22.13554], [92.60949, 21.97638], [92.67532, 22.03547], [92.70416, 22.16017], [92.86208, 22.05456], [92.89504, 21.95143], [92.93899, 22.02656], [92.99804, 21.98964], [92.99255, 22.05965], [93.04885, 22.20595], [93.15734, 22.18687], [93.14224, 22.24535], [93.19991, 22.25425], [93.18206, 22.43716], [93.13537, 22.45873], [93.11477, 22.54374], [93.134, 22.59573], [93.09417, 22.69459], [93.134, 22.92498], [93.12988, 23.05772], [93.2878, 23.00464], [93.38478, 23.13698], [93.36862, 23.35426], [93.38781, 23.36139], [93.39981, 23.38828], [93.38805, 23.4728], [93.43475, 23.68299], [93.3908, 23.7622], [93.3908, 23.92925], [93.36059, 23.93176], [93.32351, 24.04468], [93.34735, 24.10151], [93.41415, 24.07854], [93.46633, 23.97067], [93.50616, 23.94432], [93.62871, 24.00922], [93.75952, 24.0003], [93.80279, 23.92549], [93.92089, 23.95812], [94.14081, 23.83333], [94.30215, 24.23752], [94.32362, 24.27692], [94.45279, 24.56656], [94.50729, 24.59281], [94.5526, 24.70764], [94.60204, 24.70889], [94.73937, 25.00545], [94.74212, 25.13606], [94.57458, 25.20318], [94.68032, 25.47003], [94.80117, 25.49359], [95.18556, 26.07338], [95.11428, 26.1019], [95.12801, 26.38397], [95.05798, 26.45408], [95.23513, 26.68499], [95.30339, 26.65372], [95.437, 26.7083], [95.81603, 27.01335], [95.93002, 27.04149], [96.04949, 27.19428], [96.15591, 27.24572], [96.40779, 27.29818], [96.55761, 27.29928], [96.73888, 27.36638], [96.88445, 27.25046], [96.85287, 27.2065], [96.89132, 27.17474], [97.14675, 27.09041], [97.17422, 27.14052], [96.91431, 27.45752], [96.90112, 27.62149], [97.29919, 27.92233], [97.35824, 27.87256], [97.38845, 28.01329], [97.35412, 28.06663], [97.31292, 28.06784], [97.34547, 28.21385], [97.1289, 28.3619], [96.98882, 28.32564], [96.88445, 28.39452], [96.85561, 28.4875], [96.6455, 28.61657], [96.48895, 28.42955], [96.40929, 28.51526], [96.61391, 28.72742], [96.3626, 29.10607], [96.20467, 29.02325], [96.18682, 29.11087], [96.31316, 29.18643], [96.05361, 29.38167], [95.84899, 29.31464], [95.75149, 29.32063], [95.72086, 29.20797], [95.50842, 29.13487], [95.41091, 29.13007], [95.3038, 29.13847], [95.26122, 29.07727], [95.2214, 29.10727], [95.11291, 29.09527], [95.0978, 29.14446], [94.81353, 29.17804], [94.69318, 29.31739], [94.2752, 29.11687], [94.35897, 29.01965], [93.72797, 28.68821], [93.44621, 28.67189], [93.18069, 28.50319], [93.14635, 28.37035], [92.93075, 28.25671], [92.67486, 28.15018], [92.65472, 28.07632], [92.73025, 28.05814], [92.7275, 27.98662], [92.42538, 27.80092], [92.32101, 27.79363], [92.27432, 27.89077], [91.87057, 27.7195], [91.84722, 27.76325], [91.6469, 27.76358], [91.55819, 27.6144], [91.65007, 27.48287], [92.01132, 27.47352], [92.12019, 27.27829], [92.04702, 27.26861], [92.03457, 27.07334], [92.11863, 26.893], [92.05523, 26.8692], [91.83181, 26.87318], [91.50067, 26.79223], [90.67715, 26.77215], [90.48504, 26.8594], [90.39271, 26.90704], [90.30402, 26.85098], [90.04535, 26.72422], [89.86124, 26.73307], [89.63369, 26.74402], [89.42349, 26.83727], [89.3901, 26.84225], [89.38319, 26.85963], [89.37913, 26.86224], [89.1926, 26.81329], [89.12825, 26.81661], [89.09554, 26.89089], [88.95807, 26.92668], [88.92301, 26.99286], [88.8714, 26.97488], [88.86984, 27.10937], [88.74219, 27.144], [88.91901, 27.32483], [88.82981, 27.38814], [88.77517, 27.45415], [88.88091, 27.85192], [88.83559, 28.01936], [88.63235, 28.12356], [88.54858, 28.06057], [88.25332, 27.9478], [88.1278, 27.95417], [88.13378, 27.88015], [88.1973, 27.85067], [88.19107, 27.79285], [88.04008, 27.49223], [88.07277, 27.43007], [88.01646, 27.21612], [88.01587, 27.21388], [87.9887, 27.11045], [88.11719, 26.98758], [88.13422, 26.98705], [88.12302, 26.95324], [88.19107, 26.75516], [88.1659, 26.68177], [88.16452, 26.64111], [88.09963, 26.54195], [88.09414, 26.43732], [88.00895, 26.36029], [87.90115, 26.44923], [87.89085, 26.48565], [87.84193, 26.43663], [87.7918, 26.46737], [87.76004, 26.40711], [87.67893, 26.43501], [87.66803, 26.40294], [87.59175, 26.38342], [87.55274, 26.40596], [87.51571, 26.43106], [87.46566, 26.44058], [87.37314, 26.40815], [87.34568, 26.34787], [87.26568, 26.37294], [87.26587, 26.40592], [87.24682, 26.4143], [87.18863, 26.40558], [87.14751, 26.40542], [87.09147, 26.45039], [87.0707, 26.58571], [87.04691, 26.58685], [87.01559, 26.53228], [86.95912, 26.52076], [86.94543, 26.52076], [86.82898, 26.43919], [86.76797, 26.45892], [86.74025, 26.42386], [86.69124, 26.45169], [86.62686, 26.46891], [86.61313, 26.48658], [86.57073, 26.49825], [86.54258, 26.53819], [86.49726, 26.54218], [86.31564, 26.61925], [86.26235, 26.61886], [86.22513, 26.58863], [86.13596, 26.60651], [86.02729, 26.66756], [85.8492, 26.56667], [85.85126, 26.60866], [85.83126, 26.61134], [85.76907, 26.63076], [85.72315, 26.67471], [85.73483, 26.79613], [85.66239, 26.84822], [85.61621, 26.86721], [85.59461, 26.85161], [85.5757, 26.85955], [85.56471, 26.84133], [85.47752, 26.79292], [85.34302, 26.74954], [85.21159, 26.75933], [85.18046, 26.80519], [85.19291, 26.86909], [85.15883, 26.86966], [85.02635, 26.85381], [85.05592, 26.88991], [85.00536, 26.89523], [84.97186, 26.9149], [84.96687, 26.95599], [84.85754, 26.98984], [84.82913, 27.01989], [84.793, 26.9968], [84.64496, 27.04669], [84.69166, 27.21294], [84.62161, 27.33885], [84.29315, 27.39], [84.25735, 27.44941], [84.21376, 27.45218], [84.10791, 27.52399], [84.02229, 27.43836], [83.93306, 27.44939], [83.86182, 27.4241], [83.85595, 27.35797], [83.61288, 27.47013], [83.39495, 27.4798], [83.38872, 27.39276], [83.35136, 27.33885], [83.29999, 27.32778], [83.2673, 27.36235], [83.27197, 27.38309], [83.19413, 27.45632], [82.94938, 27.46036], [82.93261, 27.50328], [82.74119, 27.49838], [82.70378, 27.72122], [82.46405, 27.6716], [82.06554, 27.92222], [81.97214, 27.93322], [81.91223, 27.84995], [81.47867, 28.08303], [81.48179, 28.12148], [81.38683, 28.17638], [81.32923, 28.13521], [81.19847, 28.36284], [81.03471, 28.40054], [80.55142, 28.69182], [80.50575, 28.6706], [80.52443, 28.54897], [80.44504, 28.63098], [80.37188, 28.63371], [80.12125, 28.82346], [80.06957, 28.82763], [80.05743, 28.91479], [80.18085, 29.13649], [80.23178, 29.11626], [80.26602, 29.13938], [80.24112, 29.21414], [80.28626, 29.20327], [80.31428, 29.30784], [80.24322, 29.44299], [80.37939, 29.57098], [80.41858, 29.63581], [80.38428, 29.68513], [80.36803, 29.73865], [80.41554, 29.79451], [80.43458, 29.80466], [80.48997, 29.79566], [80.56247, 29.86661], [80.57179, 29.91422], [80.60226, 29.95732], [80.67076, 29.95732], [80.8778, 30.13384], [80.86673, 30.17321], [80.91143, 30.22173], [80.92547, 30.17193], [81.03953, 30.20059], [80.83343, 30.32023], [80.54504, 30.44936], [80.20721, 30.58541], [79.93255, 30.88288], [79.59884, 30.93943], [79.30694, 31.17357], [79.14016, 31.43403], [79.01931, 31.42817], [78.89344, 31.30481], [78.77898, 31.31209], [78.71032, 31.50197], [78.84516, 31.60631], [78.69933, 31.78723], [78.78036, 31.99478], [78.74404, 32.00384], [78.68754, 32.10256], [78.49609, 32.2762], [78.4645, 32.45367], [78.38897, 32.53938], [78.73916, 32.69438], [78.7831, 32.46873], [78.96713, 32.33655], [78.99322, 32.37948], [79.0979, 32.38051], [79.13174, 32.47766], [79.26768, 32.53277], [79.46562, 32.69668], [79.14016, 33.02545], [79.15252, 33.17156], [78.73636, 33.56521], [78.67599, 33.66445], [78.77349, 33.73871], [78.73367, 34.01121], [78.65657, 34.03195], [78.66225, 34.08858], [78.91769, 34.15452], [78.99802, 34.3027], [79.05364, 34.32482], [78.74465, 34.45174], [78.56475, 34.50835], [78.54964, 34.57283], [78.27781, 34.61484], [78.18435, 34.7998], [78.22692, 34.88771], [78.00033, 35.23954], [78.03466, 35.3785], [78.11664, 35.48022], [77.80532, 35.52058], [77.70232, 35.46244], [77.44277, 35.46132], [76.96624, 35.5932], [76.84539, 35.67356], [76.77323, 35.66062], [76.75475, 35.52617], [76.85088, 35.39754], [76.93465, 35.39866], [77.11796, 35.05419], [76.99251, 34.93349], [76.87193, 34.96906], [76.74514, 34.92488], [76.74377, 34.84039], [76.67648, 34.76371], [76.47186, 34.78965], [76.15463, 34.6429], [76.04614, 34.67566], [75.75438, 34.51827], [75.38009, 34.55021], [75.01479, 34.64629], [74.6663, 34.703], [74.58083, 34.77386], [74.31239, 34.79626], [74.12897, 34.70073], [73.96423, 34.68244], [73.93401, 34.63386], [73.93951, 34.57169], [73.89419, 34.54568], [73.88732, 34.48911], [73.74999, 34.3781], [73.74862, 34.34183], [73.8475, 34.32935], [73.90517, 34.35317], [73.98208, 34.2522], [73.90677, 34.10504], [73.88732, 34.05105], [73.91341, 34.01235], [74.21554, 34.03853], [74.25262, 34.01577], [74.26086, 33.92237], [74.14001, 33.83002], [74.05898, 33.82089], [74.00891, 33.75437], [73.96423, 33.73071], [73.98968, 33.66155], [73.97367, 33.64061], [74.03576, 33.56718], [74.10115, 33.56392], [74.18121, 33.4745], [74.17983, 33.3679], [74.08782, 33.26232], [74.01366, 33.25199], [74.02144, 33.18908], [74.15374, 33.13477], [74.17571, 33.07495], [74.31854, 33.02891], [74.34875, 32.97823], [74.31227, 32.92795], [74.41467, 32.90563], [74.45312, 32.77755], [74.6289, 32.75561], [74.64675, 32.82604], [74.7113, 32.84219], [74.65345, 32.71225], [74.69542, 32.66792], [74.64424, 32.60985], [74.65251, 32.56416], [74.67431, 32.56676], [74.68362, 32.49298], [74.84725, 32.49075], [74.97634, 32.45367], [75.03265, 32.49538], [75.28259, 32.36556], [75.38046, 32.26836], [75.25649, 32.10187], [75.00793, 32.03786], [74.9269, 32.0658], [74.86236, 32.04485], [74.79919, 31.95983], [74.58907, 31.87824], [74.47771, 31.72227], [74.57498, 31.60382], [74.61517, 31.55698], [74.59319, 31.50197], [74.64713, 31.45605], [74.59773, 31.4136], [74.53223, 31.30321], [74.51629, 31.13829], [74.56023, 31.08303], [74.60281, 31.10419], [74.60006, 31.13711], [74.6852, 31.12771], [74.67971, 31.05479], [74.5616, 31.04153], [73.88993, 30.36305], [73.95736, 30.28466], [73.97225, 30.19829], [73.80299, 30.06969], [73.58665, 30.01848], [73.3962, 29.94707], [73.28094, 29.56646], [73.05886, 29.1878], [73.01337, 29.16422], [72.94272, 29.02487], [72.40402, 28.78283], [72.29495, 28.66367], [72.20329, 28.3869], [71.9244, 28.11555], [71.89921, 27.96035], [70.79054, 27.68423], [70.60927, 28.02178], [70.37307, 28.01208], [70.12502, 27.8057], [70.03136, 27.56627], [69.58519, 27.18109], [69.50904, 26.74892], [69.88555, 26.56836], [70.05584, 26.60398], [70.17532, 26.55362], [70.17532, 26.24118], [70.08193, 26.08094], [70.0985, 25.93238], [70.2687, 25.71156], [70.37444, 25.67443], [70.53649, 25.68928], [70.60378, 25.71898], [70.67382, 25.68186], [70.66695, 25.39314], [70.89148, 25.15064], [70.94002, 24.92843], [71.09405, 24.69017], [70.97594, 24.60904], [71.00341, 24.46038], [71.12838, 24.42662], [71.04461, 24.34657], [70.94985, 24.3791], [70.85784, 24.30903], [70.88393, 24.27398], [70.71502, 24.23517], [70.57906, 24.27774], [70.5667, 24.43787], [70.11712, 24.30915], [70.03428, 24.172], [69.73335, 24.17007], [69.59579, 24.29777], [69.29778, 24.28712], [69.19341, 24.25646], [69.07806, 24.29777], [68.97781, 24.26021], [68.90914, 24.33156], [68.7416, 24.31904], [68.74643, 23.97027], [68.39339, 23.96838], [68.20763, 23.85849], [68.11329, 23.53945], [76.59015, 5.591], [79.50447, 8.91876], [79.42124, 9.80115], [80.48418, 10.20786], [89.08044, 21.41871]]]]
22585           }
22586         }, {
22587           type: "Feature",
22588           properties: {
22589             wikidata: "Q9143535",
22590             nameEn: "Akrotiri",
22591             country: "GB",
22592             groups: ["Q644636", "Q37362", "BOTS", "145", "142", "UN"],
22593             level: "subterritory",
22594             driveSide: "left",
22595             callingCodes: ["357"]
22596           },
22597           geometry: {
22598             type: "MultiPolygon",
22599             coordinates: [[[[32.86014, 34.70585], [32.82717, 34.70622], [32.79433, 34.67883], [32.76136, 34.68318], [32.75515, 34.64985], [32.74412, 34.43926], [33.26744, 34.49942], [33.0138, 34.64424], [32.96968, 34.64046], [32.96718, 34.63446], [32.95891, 34.62919], [32.95323, 34.64075], [32.95471, 34.64528], [32.94976, 34.65204], [32.94796, 34.6587], [32.95325, 34.66462], [32.97079, 34.66112], [32.97736, 34.65277], [32.99014, 34.65518], [32.98668, 34.67268], [32.99135, 34.68061], [32.95539, 34.68471], [32.94683, 34.67907], [32.94379, 34.67111], [32.93693, 34.67027], [32.93449, 34.66241], [32.92807, 34.66736], [32.93043, 34.67091], [32.91398, 34.67343], [32.9068, 34.66102], [32.86167, 34.68734], [32.86014, 34.70585]]]]
22600           }
22601         }, {
22602           type: "Feature",
22603           properties: {
22604             wikidata: "Q9206745",
22605             nameEn: "Dhekelia",
22606             country: "GB",
22607             groups: ["Q644636", "Q37362", "BOTS", "145", "142", "UN"],
22608             level: "subterritory",
22609             driveSide: "left",
22610             callingCodes: ["357"]
22611           },
22612           geometry: {
22613             type: "MultiPolygon",
22614             coordinates: [[[[33.70575, 34.97947], [33.83531, 34.73974], [33.98684, 34.76642], [33.90075, 34.96623], [33.86432, 34.97592], [33.84811, 34.97075], [33.83505, 34.98108], [33.85621, 34.98956], [33.85891, 35.001], [33.85216, 35.00579], [33.84045, 35.00616], [33.82875, 35.01685], [33.83055, 35.02865], [33.81524, 35.04192], [33.8012, 35.04786], [33.82051, 35.0667], [33.8355, 35.05777], [33.85261, 35.0574], [33.88367, 35.07877], [33.89485, 35.06873], [33.90247, 35.07686], [33.91299, 35.07579], [33.91789, 35.08688], [33.89853, 35.11377], [33.88737, 35.11408], [33.88943, 35.12007], [33.88561, 35.12449], [33.87224, 35.12293], [33.87622, 35.10457], [33.87097, 35.09389], [33.87479, 35.08881], [33.8541, 35.07201], [33.84168, 35.06823], [33.82067, 35.07826], [33.78581, 35.05104], [33.76106, 35.04253], [33.73824, 35.05321], [33.71482, 35.03722], [33.70209, 35.04882], [33.7161, 35.07279], [33.70861, 35.07644], [33.69095, 35.06237], [33.68474, 35.06602], [33.67742, 35.05963], [33.67678, 35.03866], [33.69938, 35.03123], [33.69731, 35.01754], [33.71514, 35.00294], [33.70639, 34.99303], [33.70575, 34.97947]], [[33.77312, 34.9976], [33.77553, 34.99518], [33.78516, 34.99582], [33.79191, 34.98914], [33.78917, 34.98854], [33.78571, 34.98951], [33.78318, 34.98699], [33.78149, 34.98854], [33.77843, 34.988], [33.7778, 34.98981], [33.76738, 34.99188], [33.76605, 34.99543], [33.75682, 34.99916], [33.75994, 35.00113], [33.77312, 34.9976]], [[33.74144, 35.01053], [33.7343, 35.01178], [33.73781, 35.02181], [33.74265, 35.02329], [33.74983, 35.02274], [33.7492, 35.01319], [33.74144, 35.01053]]]]
22615           }
22616         }, {
22617           type: "Feature",
22618           properties: {
22619             wikidata: "Q16390686",
22620             nameEn: "Peninsular Spain",
22621             country: "ES",
22622             groups: ["Q12837", "EU", "039", "150", "UN"],
22623             callingCodes: ["34"]
22624           },
22625           geometry: {
22626             type: "MultiPolygon",
22627             coordinates: [[[[3.75438, 42.33445], [3.17156, 42.43545], [3.11379, 42.43646], [3.10027, 42.42621], [3.08167, 42.42748], [3.03734, 42.47363], [2.96518, 42.46692], [2.94283, 42.48174], [2.92107, 42.4573], [2.88413, 42.45938], [2.86983, 42.46843], [2.85675, 42.45444], [2.84335, 42.45724], [2.77464, 42.41046], [2.75497, 42.42578], [2.72056, 42.42298], [2.65311, 42.38771], [2.6747, 42.33974], [2.57934, 42.35808], [2.55516, 42.35351], [2.54382, 42.33406], [2.48457, 42.33933], [2.43508, 42.37568], [2.43299, 42.39423], [2.38504, 42.39977], [2.25551, 42.43757], [2.20578, 42.41633], [2.16599, 42.42314], [2.12789, 42.41291], [2.11621, 42.38393], [2.06241, 42.35906], [2.00488, 42.35399], [1.96482, 42.37787], [1.9574, 42.42401], [1.94084, 42.43039], [1.94061, 42.43333], [1.94292, 42.44316], [1.93663, 42.45439], [1.88853, 42.4501], [1.83037, 42.48395], [1.76335, 42.48863], [1.72515, 42.50338], [1.70571, 42.48867], [1.66826, 42.50779], [1.65674, 42.47125], [1.58933, 42.46275], [1.57953, 42.44957], [1.55937, 42.45808], [1.55073, 42.43299], [1.5127, 42.42959], [1.44529, 42.43724], [1.43838, 42.47848], [1.41648, 42.48315], [1.46661, 42.50949], [1.44759, 42.54431], [1.41245, 42.53539], [1.4234, 42.55959], [1.44529, 42.56722], [1.42512, 42.58292], [1.44197, 42.60217], [1.35562, 42.71944], [1.15928, 42.71407], [1.0804, 42.78569], [0.98292, 42.78754], [0.96166, 42.80629], [0.93089, 42.79154], [0.711, 42.86372], [0.66121, 42.84021], [0.65421, 42.75872], [0.67873, 42.69458], [0.40214, 42.69779], [0.36251, 42.72282], [0.29407, 42.67431], [0.25336, 42.7174], [0.17569, 42.73424], [-0.02468, 42.68513], [-0.10519, 42.72761], [-0.16141, 42.79535], [-0.17939, 42.78974], [-0.3122, 42.84788], [-0.38833, 42.80132], [-0.41319, 42.80776], [-0.44334, 42.79939], [-0.50863, 42.82713], [-0.55497, 42.77846], [-0.67637, 42.88303], [-0.69837, 42.87945], [-0.72608, 42.89318], [-0.73422, 42.91228], [-0.72037, 42.92541], [-0.75478, 42.96916], [-0.81652, 42.95166], [-0.97133, 42.96239], [-1.00963, 42.99279], [-1.10333, 43.0059], [-1.22881, 43.05534], [-1.25244, 43.04164], [-1.30531, 43.06859], [-1.30052, 43.09581], [-1.27118, 43.11961], [-1.32209, 43.1127], [-1.34419, 43.09665], [-1.35272, 43.02658], [-1.44067, 43.047], [-1.47555, 43.08372], [-1.41562, 43.12815], [-1.3758, 43.24511], [-1.40942, 43.27272], [-1.45289, 43.27049], [-1.50992, 43.29481], [-1.55963, 43.28828], [-1.57674, 43.25269], [-1.61341, 43.25269], [-1.63052, 43.28591], [-1.62481, 43.30726], [-1.69407, 43.31378], [-1.73074, 43.29481], [-1.7397, 43.32979], [-1.75079, 43.3317], [-1.75334, 43.34107], [-1.77068, 43.34396], [-1.78714, 43.35476], [-1.78332, 43.36399], [-1.79319, 43.37497], [-1.77289, 43.38957], [-1.81005, 43.59738], [-10.14298, 44.17365], [-11.19304, 41.83075], [-8.87157, 41.86488], [-8.81794, 41.90375], [-8.75712, 41.92833], [-8.74606, 41.9469], [-8.7478, 41.96282], [-8.69071, 41.98862], [-8.6681, 41.99703], [-8.65832, 42.02972], [-8.64626, 42.03668], [-8.63791, 42.04691], [-8.59493, 42.05708], [-8.58086, 42.05147], [-8.54563, 42.0537], [-8.5252, 42.06264], [-8.52837, 42.07658], [-8.48185, 42.0811], [-8.44123, 42.08218], [-8.42512, 42.07199], [-8.40143, 42.08052], [-8.38323, 42.07683], [-8.36353, 42.09065], [-8.33912, 42.08358], [-8.32161, 42.10218], [-8.29809, 42.106], [-8.2732, 42.12396], [-8.24681, 42.13993], [-8.22406, 42.1328], [-8.1986, 42.15402], [-8.18947, 42.13853], [-8.19406, 42.12141], [-8.18178, 42.06436], [-8.11729, 42.08537], [-8.08847, 42.05767], [-8.08796, 42.01398], [-8.16232, 41.9828], [-8.2185, 41.91237], [-8.19551, 41.87459], [-8.16944, 41.87944], [-8.16455, 41.81753], [-8.0961, 41.81024], [-8.01136, 41.83453], [-7.9804, 41.87337], [-7.92336, 41.8758], [-7.90707, 41.92432], [-7.88751, 41.92553], [-7.88055, 41.84571], [-7.84188, 41.88065], [-7.69848, 41.90977], [-7.65774, 41.88308], [-7.58603, 41.87944], [-7.62188, 41.83089], [-7.52737, 41.83939], [-7.49803, 41.87095], [-7.45566, 41.86488], [-7.44759, 41.84451], [-7.42854, 41.83262], [-7.42864, 41.80589], [-7.37092, 41.85031], [-7.32366, 41.8406], [-7.18677, 41.88793], [-7.18549, 41.97515], [-7.14115, 41.98855], [-7.08574, 41.97401], [-7.07596, 41.94977], [-7.01078, 41.94977], [-6.98144, 41.9728], [-6.95537, 41.96553], [-6.94396, 41.94403], [-6.82174, 41.94493], [-6.81196, 41.99097], [-6.76959, 41.98734], [-6.75004, 41.94129], [-6.61967, 41.94008], [-6.58544, 41.96674], [-6.5447, 41.94371], [-6.56752, 41.88429], [-6.51374, 41.8758], [-6.56426, 41.74219], [-6.54633, 41.68623], [-6.49907, 41.65823], [-6.44204, 41.68258], [-6.29863, 41.66432], [-6.19128, 41.57638], [-6.26777, 41.48796], [-6.3306, 41.37677], [-6.38553, 41.38655], [-6.38551, 41.35274], [-6.55937, 41.24417], [-6.65046, 41.24725], [-6.68286, 41.21641], [-6.69711, 41.1858], [-6.77319, 41.13049], [-6.75655, 41.10187], [-6.79241, 41.05397], [-6.80942, 41.03629], [-6.84781, 41.02692], [-6.88843, 41.03027], [-6.913, 41.03922], [-6.9357, 41.02888], [-6.8527, 40.93958], [-6.84292, 40.89771], [-6.80707, 40.88047], [-6.79892, 40.84842], [-6.82337, 40.84472], [-6.82826, 40.74603], [-6.79567, 40.65955], [-6.84292, 40.56801], [-6.80218, 40.55067], [-6.7973, 40.51723], [-6.84944, 40.46394], [-6.84618, 40.42177], [-6.78426, 40.36468], [-6.80218, 40.33239], [-6.86085, 40.2976], [-6.86085, 40.26776], [-7.00426, 40.23169], [-7.02544, 40.18564], [-7.00589, 40.12087], [-6.94233, 40.10716], [-6.86737, 40.01986], [-6.91463, 39.86618], [-6.97492, 39.81488], [-7.01613, 39.66877], [-7.24707, 39.66576], [-7.33507, 39.64569], [-7.54121, 39.66717], [-7.49477, 39.58794], [-7.2927, 39.45847], [-7.3149, 39.34857], [-7.23403, 39.27579], [-7.23566, 39.20132], [-7.12811, 39.17101], [-7.14929, 39.11287], [-7.10692, 39.10275], [-7.04011, 39.11919], [-6.97004, 39.07619], [-6.95211, 39.0243], [-7.051, 38.907], [-7.03848, 38.87221], [-7.26174, 38.72107], [-7.265, 38.61674], [-7.32529, 38.44336], [-7.15581, 38.27597], [-7.09389, 38.17227], [-6.93418, 38.21454], [-7.00375, 38.01914], [-7.05966, 38.01966], [-7.10366, 38.04404], [-7.12648, 38.00296], [-7.24544, 37.98884], [-7.27314, 37.90145], [-7.33441, 37.81193], [-7.41981, 37.75729], [-7.51759, 37.56119], [-7.46878, 37.47127], [-7.43974, 37.38913], [-7.43227, 37.25152], [-7.41854, 37.23813], [-7.41133, 37.20314], [-7.39769, 37.16868], [-7.37282, 36.96896], [-7.2725, 35.73269], [-5.10878, 36.05227], [-2.27707, 35.35051], [3.75438, 42.33445]], [[-5.27801, 36.14942], [-5.34064, 36.03744], [-5.40526, 36.15488], [-5.34536, 36.15501], [-5.33822, 36.15272], [-5.27801, 36.14942]]], [[[1.99838, 42.44682], [2.01564, 42.45171], [1.99216, 42.46208], [1.98579, 42.47486], [1.99766, 42.4858], [1.98916, 42.49351], [1.98022, 42.49569], [1.97697, 42.48568], [1.97227, 42.48487], [1.97003, 42.48081], [1.96215, 42.47854], [1.95606, 42.45785], [1.96125, 42.45364], [1.98378, 42.44697], [1.99838, 42.44682]]]]
22628           }
22629         }, {
22630           type: "Feature",
22631           properties: {
22632             wikidata: "Q98059339",
22633             nameEn: "Mainland Norway",
22634             country: "NO",
22635             groups: ["154", "150", "UN"],
22636             callingCodes: ["47"]
22637           },
22638           geometry: {
22639             type: "MultiPolygon",
22640             coordinates: [[[[10.40861, 58.38489], [10.64958, 58.89391], [11.08911, 58.98745], [11.15367, 59.07862], [11.34459, 59.11672], [11.4601, 58.99022], [11.45199, 58.89604], [11.65732, 58.90177], [11.8213, 59.24985], [11.69297, 59.59442], [11.92112, 59.69531], [11.87121, 59.86039], [12.15641, 59.8926], [12.36317, 59.99259], [12.52003, 60.13846], [12.59133, 60.50559], [12.2277, 61.02442], [12.69115, 61.06584], [12.86939, 61.35427], [12.57707, 61.56547], [12.40595, 61.57226], [12.14746, 61.7147], [12.29187, 62.25699], [12.07085, 62.6297], [12.19919, 63.00104], [11.98529, 63.27487], [12.19919, 63.47935], [12.14928, 63.59373], [12.74105, 64.02171], [13.23411, 64.09087], [13.98222, 64.00953], [14.16051, 64.18725], [14.11117, 64.46674], [13.64276, 64.58402], [14.50926, 65.31786], [14.53778, 66.12399], [15.05113, 66.15572], [15.49318, 66.28509], [15.37197, 66.48217], [16.35589, 67.06419], [16.39154, 67.21653], [16.09922, 67.4364], [16.12774, 67.52106], [16.38441, 67.52923], [16.7409, 67.91037], [17.30416, 68.11591], [17.90787, 67.96537], [18.13836, 68.20874], [18.1241, 68.53721], [18.39503, 68.58672], [18.63032, 68.50849], [18.97255, 68.52416], [19.93508, 68.35911], [20.22027, 68.48759], [19.95647, 68.55546], [20.22027, 68.67246], [20.33435, 68.80174], [20.28444, 68.93283], [20.0695, 69.04469], [20.55258, 69.06069], [20.72171, 69.11874], [21.05775, 69.0356], [21.11099, 69.10291], [20.98641, 69.18809], [21.00732, 69.22755], [21.27827, 69.31281], [21.63833, 69.27485], [22.27276, 68.89514], [22.38367, 68.71561], [22.53321, 68.74393], [23.13064, 68.64684], [23.68017, 68.70276], [23.781, 68.84514], [24.02299, 68.81601], [24.18432, 68.73936], [24.74898, 68.65143], [24.90023, 68.55579], [24.93048, 68.61102], [25.10189, 68.63307], [25.12206, 68.78684], [25.42455, 68.90328], [25.61613, 68.89602], [25.75729, 68.99383], [25.69679, 69.27039], [25.96904, 69.68397], [26.40261, 69.91377], [26.64461, 69.96565], [27.05802, 69.92069], [27.57226, 70.06215], [27.95542, 70.0965], [27.97558, 69.99671], [28.32849, 69.88605], [28.36883, 69.81658], [29.12697, 69.69193], [29.31664, 69.47994], [28.8629, 69.22395], [28.81248, 69.11997], [28.91738, 69.04774], [29.0444, 69.0119], [29.26623, 69.13794], [29.27631, 69.2811], [29.97205, 69.41623], [30.16363, 69.65244], [30.52662, 69.54699], [30.95011, 69.54699], [30.84095, 69.80584], [31.59909, 70.16571], [32.07813, 72.01005], [-11.60274, 67.73467], [7.28637, 57.35913], [10.40861, 58.38489]]]]
22641           }
22642         }, {
22643           type: "Feature",
22644           properties: {
22645             wikidata: "Q98543636",
22646             nameEn: "Mainland Ecuador",
22647             country: "EC",
22648             groups: ["005", "419", "019", "UN"],
22649             callingCodes: ["593"]
22650           },
22651           geometry: {
22652             type: "MultiPolygon",
22653             coordinates: [[[[-84.52388, -3.36941], [-80.30602, -3.39149], [-80.20647, -3.431], [-80.24123, -3.46124], [-80.24586, -3.48677], [-80.23651, -3.48652], [-80.22629, -3.501], [-80.20535, -3.51667], [-80.21642, -3.5888], [-80.19848, -3.59249], [-80.18741, -3.63994], [-80.19926, -3.68894], [-80.13232, -3.90317], [-80.46386, -4.01342], [-80.4822, -4.05477], [-80.45023, -4.20938], [-80.32114, -4.21323], [-80.46386, -4.41516], [-80.39256, -4.48269], [-80.13945, -4.29786], [-79.79722, -4.47558], [-79.59402, -4.46848], [-79.26248, -4.95167], [-79.1162, -4.97774], [-79.01659, -5.01481], [-78.85149, -4.66795], [-78.68394, -4.60754], [-78.34362, -3.38633], [-78.24589, -3.39907], [-78.22642, -3.51113], [-78.14324, -3.47653], [-78.19369, -3.36431], [-77.94147, -3.05454], [-76.6324, -2.58397], [-76.05203, -2.12179], [-75.57429, -1.55961], [-75.3872, -0.9374], [-75.22862, -0.95588], [-75.22862, -0.60048], [-75.53615, -0.19213], [-75.60169, -0.18708], [-75.61997, -0.10012], [-75.40192, -0.17196], [-75.25764, -0.11943], [-75.82927, 0.09578], [-76.23441, 0.42294], [-76.41215, 0.38228], [-76.4094, 0.24015], [-76.89177, 0.24736], [-77.52001, 0.40782], [-77.49984, 0.64476], [-77.67815, 0.73863], [-77.66416, 0.81604], [-77.68613, 0.83029], [-77.7148, 0.85003], [-77.85677, 0.80197], [-78.42749, 1.15389], [-78.87137, 1.47457], [-82.12561, 4.00341], [-84.52388, -3.36941]]]]
22654           }
22655         }, {
22656           type: "Feature",
22657           properties: {
22658             m49: "001",
22659             wikidata: "Q2",
22660             nameEn: "World",
22661             aliases: ["Earth", "Planet"],
22662             level: "world"
22663           },
22664           geometry: null
22665         }, {
22666           type: "Feature",
22667           properties: {
22668             m49: "002",
22669             wikidata: "Q15",
22670             nameEn: "Africa",
22671             level: "region"
22672           },
22673           geometry: null
22674         }, {
22675           type: "Feature",
22676           properties: {
22677             m49: "003",
22678             wikidata: "Q49",
22679             nameEn: "North America",
22680             level: "subregion"
22681           },
22682           geometry: null
22683         }, {
22684           type: "Feature",
22685           properties: {
22686             m49: "005",
22687             wikidata: "Q18",
22688             nameEn: "South America",
22689             level: "intermediateRegion"
22690           },
22691           geometry: null
22692         }, {
22693           type: "Feature",
22694           properties: {
22695             m49: "009",
22696             wikidata: "Q538",
22697             nameEn: "Oceania",
22698             level: "region"
22699           },
22700           geometry: null
22701         }, {
22702           type: "Feature",
22703           properties: {
22704             m49: "011",
22705             wikidata: "Q4412",
22706             nameEn: "Western Africa",
22707             level: "intermediateRegion"
22708           },
22709           geometry: null
22710         }, {
22711           type: "Feature",
22712           properties: {
22713             m49: "013",
22714             wikidata: "Q27611",
22715             nameEn: "Central America",
22716             level: "intermediateRegion"
22717           },
22718           geometry: null
22719         }, {
22720           type: "Feature",
22721           properties: {
22722             m49: "014",
22723             wikidata: "Q27407",
22724             nameEn: "Eastern Africa",
22725             level: "intermediateRegion"
22726           },
22727           geometry: null
22728         }, {
22729           type: "Feature",
22730           properties: {
22731             m49: "015",
22732             wikidata: "Q27381",
22733             nameEn: "Northern Africa",
22734             level: "subregion"
22735           },
22736           geometry: null
22737         }, {
22738           type: "Feature",
22739           properties: {
22740             m49: "017",
22741             wikidata: "Q27433",
22742             nameEn: "Middle Africa",
22743             level: "intermediateRegion"
22744           },
22745           geometry: null
22746         }, {
22747           type: "Feature",
22748           properties: {
22749             m49: "018",
22750             wikidata: "Q27394",
22751             nameEn: "Southern Africa",
22752             level: "intermediateRegion"
22753           },
22754           geometry: null
22755         }, {
22756           type: "Feature",
22757           properties: {
22758             m49: "019",
22759             wikidata: "Q828",
22760             nameEn: "Americas",
22761             level: "region"
22762           },
22763           geometry: null
22764         }, {
22765           type: "Feature",
22766           properties: {
22767             m49: "021",
22768             wikidata: "Q2017699",
22769             nameEn: "Northern America",
22770             level: "subregion"
22771           },
22772           geometry: null
22773         }, {
22774           type: "Feature",
22775           properties: {
22776             m49: "029",
22777             wikidata: "Q664609",
22778             nameEn: "Caribbean",
22779             level: "intermediateRegion"
22780           },
22781           geometry: null
22782         }, {
22783           type: "Feature",
22784           properties: {
22785             m49: "030",
22786             wikidata: "Q27231",
22787             nameEn: "Eastern Asia",
22788             level: "subregion"
22789           },
22790           geometry: null
22791         }, {
22792           type: "Feature",
22793           properties: {
22794             m49: "034",
22795             wikidata: "Q771405",
22796             nameEn: "Southern Asia",
22797             level: "subregion"
22798           },
22799           geometry: null
22800         }, {
22801           type: "Feature",
22802           properties: {
22803             m49: "035",
22804             wikidata: "Q11708",
22805             nameEn: "South-eastern Asia",
22806             level: "subregion"
22807           },
22808           geometry: null
22809         }, {
22810           type: "Feature",
22811           properties: {
22812             m49: "039",
22813             wikidata: "Q27449",
22814             nameEn: "Southern Europe",
22815             level: "subregion"
22816           },
22817           geometry: null
22818         }, {
22819           type: "Feature",
22820           properties: {
22821             m49: "053",
22822             wikidata: "Q45256",
22823             nameEn: "Australia and New Zealand",
22824             aliases: ["Australasia"],
22825             level: "subregion"
22826           },
22827           geometry: null
22828         }, {
22829           type: "Feature",
22830           properties: {
22831             m49: "054",
22832             wikidata: "Q37394",
22833             nameEn: "Melanesia",
22834             level: "subregion"
22835           },
22836           geometry: null
22837         }, {
22838           type: "Feature",
22839           properties: {
22840             m49: "057",
22841             wikidata: "Q3359409",
22842             nameEn: "Micronesia",
22843             level: "subregion"
22844           },
22845           geometry: null
22846         }, {
22847           type: "Feature",
22848           properties: {
22849             m49: "061",
22850             wikidata: "Q35942",
22851             nameEn: "Polynesia",
22852             level: "subregion"
22853           },
22854           geometry: null
22855         }, {
22856           type: "Feature",
22857           properties: {
22858             m49: "142",
22859             wikidata: "Q48",
22860             nameEn: "Asia",
22861             level: "region"
22862           },
22863           geometry: null
22864         }, {
22865           type: "Feature",
22866           properties: {
22867             m49: "143",
22868             wikidata: "Q27275",
22869             nameEn: "Central Asia",
22870             level: "subregion"
22871           },
22872           geometry: null
22873         }, {
22874           type: "Feature",
22875           properties: {
22876             m49: "145",
22877             wikidata: "Q27293",
22878             nameEn: "Western Asia",
22879             level: "subregion"
22880           },
22881           geometry: null
22882         }, {
22883           type: "Feature",
22884           properties: {
22885             m49: "150",
22886             wikidata: "Q46",
22887             nameEn: "Europe",
22888             level: "region"
22889           },
22890           geometry: null
22891         }, {
22892           type: "Feature",
22893           properties: {
22894             m49: "151",
22895             wikidata: "Q27468",
22896             nameEn: "Eastern Europe",
22897             level: "subregion"
22898           },
22899           geometry: null
22900         }, {
22901           type: "Feature",
22902           properties: {
22903             m49: "154",
22904             wikidata: "Q27479",
22905             nameEn: "Northern Europe",
22906             level: "subregion"
22907           },
22908           geometry: null
22909         }, {
22910           type: "Feature",
22911           properties: {
22912             m49: "155",
22913             wikidata: "Q27496",
22914             nameEn: "Western Europe",
22915             level: "subregion"
22916           },
22917           geometry: null
22918         }, {
22919           type: "Feature",
22920           properties: {
22921             m49: "202",
22922             wikidata: "Q132959",
22923             nameEn: "Sub-Saharan Africa",
22924             level: "subregion"
22925           },
22926           geometry: null
22927         }, {
22928           type: "Feature",
22929           properties: {
22930             m49: "419",
22931             wikidata: "Q72829598",
22932             nameEn: "Latin America and the Caribbean",
22933             level: "subregion"
22934           },
22935           geometry: null
22936         }, {
22937           type: "Feature",
22938           properties: {
22939             m49: "680",
22940             wikidata: "Q3405693",
22941             nameEn: "Sark",
22942             country: "GB",
22943             groups: ["GG", "830", "Q185086", "154", "150", "UN"],
22944             level: "subterritory",
22945             driveSide: "left",
22946             roadSpeedUnit: "mph",
22947             roadHeightUnit: "ft",
22948             callingCodes: ["44 01481"]
22949           },
22950           geometry: {
22951             type: "MultiPolygon",
22952             coordinates: [[[[-2.36485, 49.48223], [-2.65349, 49.15373], [-2.09454, 49.46288], [-2.36485, 49.48223]]]]
22953           }
22954         }, {
22955           type: "Feature",
22956           properties: {
22957             m49: "830",
22958             wikidata: "Q42314",
22959             nameEn: "Channel Islands",
22960             level: "intermediateRegion"
22961           },
22962           geometry: null
22963         }, {
22964           type: "Feature",
22965           properties: {
22966             iso1A2: "AC",
22967             iso1A3: "ASC",
22968             wikidata: "Q46197",
22969             nameEn: "Ascension Island",
22970             aliases: ["SH-AC"],
22971             country: "GB",
22972             groups: ["SH", "BOTS", "011", "202", "002", "UN"],
22973             isoStatus: "excRes",
22974             driveSide: "left",
22975             roadSpeedUnit: "mph",
22976             roadHeightUnit: "ft",
22977             callingCodes: ["247"]
22978           },
22979           geometry: {
22980             type: "MultiPolygon",
22981             coordinates: [[[[-14.82771, -8.70814], [-13.33271, -8.07391], [-14.91926, -6.63386], [-14.82771, -8.70814]]]]
22982           }
22983         }, {
22984           type: "Feature",
22985           properties: {
22986             iso1A2: "AD",
22987             iso1A3: "AND",
22988             iso1N3: "020",
22989             wikidata: "Q228",
22990             nameEn: "Andorra",
22991             groups: ["Q12837", "039", "150", "UN"],
22992             callingCodes: ["376"]
22993           },
22994           geometry: {
22995             type: "MultiPolygon",
22996             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]]]]
22997           }
22998         }, {
22999           type: "Feature",
23000           properties: {
23001             iso1A2: "AE",
23002             iso1A3: "ARE",
23003             iso1N3: "784",
23004             wikidata: "Q878",
23005             nameEn: "United Arab Emirates",
23006             groups: ["145", "142", "UN"],
23007             callingCodes: ["971"]
23008           },
23009           geometry: {
23010             type: "MultiPolygon",
23011             coordinates: [[[[56.26534, 25.62825], [56.25341, 25.61443], [56.26636, 25.60643], [56.25365, 25.60211], [56.20473, 25.61119], [56.18363, 25.65508], [56.14826, 25.66351], [56.13579, 25.73524], [56.17416, 25.77239], [56.13963, 25.82765], [56.19334, 25.9795], [56.15498, 26.06828], [56.08666, 26.05038], [55.81777, 26.18798], [55.14145, 25.62624], [53.97892, 24.64436], [52.82259, 25.51697], [52.35509, 25.00368], [52.02277, 24.75635], [51.83108, 24.71675], [51.58834, 24.66608], [51.41644, 24.39615], [51.58871, 24.27256], [51.59617, 24.12041], [52.56622, 22.94341], [55.13599, 22.63334], [55.2137, 22.71065], [55.22634, 23.10378], [55.57358, 23.669], [55.48677, 23.94946], [55.73301, 24.05994], [55.8308, 24.01633], [56.01799, 24.07426], [55.95472, 24.2172], [55.83367, 24.20193], [55.77658, 24.23476], [55.76558, 24.23227], [55.75257, 24.23466], [55.75382, 24.2466], [55.75939, 24.26114], [55.76781, 24.26209], [55.79145, 24.27914], [55.80747, 24.31069], [55.83395, 24.32776], [55.83271, 24.41521], [55.76461, 24.5287], [55.83271, 24.68567], [55.83408, 24.77858], [55.81348, 24.80102], [55.81116, 24.9116], [55.85094, 24.96858], [55.90849, 24.96771], [55.96316, 25.00857], [56.05715, 24.95727], [56.05106, 24.87461], [55.97467, 24.89639], [55.97836, 24.87673], [56.03535, 24.81161], [56.06128, 24.74457], [56.13684, 24.73699], [56.20062, 24.78565], [56.20568, 24.85063], [56.30269, 24.88334], [56.34873, 24.93205], [56.3227, 24.97284], [56.86325, 25.03856], [56.82555, 25.7713], [56.26534, 25.62825]], [[56.26062, 25.33108], [56.3005, 25.31815], [56.3111, 25.30107], [56.35172, 25.30681], [56.34438, 25.26653], [56.27628, 25.23404], [56.24341, 25.22867], [56.20872, 25.24104], [56.20838, 25.25668], [56.24465, 25.27505], [56.25008, 25.28843], [56.23362, 25.31253], [56.26062, 25.33108]]], [[[56.28423, 25.26344], [56.29379, 25.2754], [56.28102, 25.28486], [56.2716, 25.27916], [56.27086, 25.26128], [56.28423, 25.26344]]]]
23012           }
23013         }, {
23014           type: "Feature",
23015           properties: {
23016             iso1A2: "AF",
23017             iso1A3: "AFG",
23018             iso1N3: "004",
23019             wikidata: "Q889",
23020             nameEn: "Afghanistan",
23021             groups: ["034", "142", "UN"],
23022             callingCodes: ["93"]
23023           },
23024           geometry: {
23025             type: "MultiPolygon",
23026             coordinates: [[[[70.61526, 38.34774], [70.60407, 38.28046], [70.54673, 38.24541], [70.4898, 38.12546], [70.17206, 37.93276], [70.1863, 37.84296], [70.27694, 37.81258], [70.28243, 37.66706], [70.15015, 37.52519], [69.95971, 37.5659], [69.93362, 37.61378], [69.84435, 37.60616], [69.80041, 37.5746], [69.51888, 37.5844], [69.44954, 37.4869], [69.36645, 37.40462], [69.45022, 37.23315], [69.39529, 37.16752], [69.25152, 37.09426], [69.03274, 37.25174], [68.96407, 37.32603], [68.88168, 37.33368], [68.91189, 37.26704], [68.80889, 37.32494], [68.81438, 37.23862], [68.6798, 37.27906], [68.61851, 37.19815], [68.41888, 37.13906], [68.41201, 37.10402], [68.29253, 37.10621], [68.27605, 37.00977], [68.18542, 37.02074], [68.02194, 36.91923], [67.87917, 37.0591], [67.7803, 37.08978], [67.78329, 37.1834], [67.51868, 37.26102], [67.2581, 37.17216], [67.2224, 37.24545], [67.13039, 37.27168], [67.08232, 37.35469], [66.95598, 37.40162], [66.64699, 37.32958], [66.55743, 37.35409], [66.30993, 37.32409], [65.72274, 37.55438], [65.64137, 37.45061], [65.64263, 37.34388], [65.51778, 37.23881], [64.97945, 37.21913], [64.61141, 36.6351], [64.62514, 36.44311], [64.57295, 36.34362], [64.43288, 36.24401], [64.05385, 36.10433], [63.98519, 36.03773], [63.56496, 35.95106], [63.53475, 35.90881], [63.29579, 35.85985], [63.12276, 35.86208], [63.10318, 35.81782], [63.23262, 35.67487], [63.10079, 35.63024], [63.12276, 35.53196], [63.0898, 35.43131], [62.90853, 35.37086], [62.74098, 35.25432], [62.62288, 35.22067], [62.48006, 35.28796], [62.29878, 35.13312], [62.29191, 35.25964], [62.15871, 35.33278], [62.05709, 35.43803], [61.97743, 35.4604], [61.77693, 35.41341], [61.58742, 35.43803], [61.27371, 35.61482], [61.18187, 35.30249], [61.0991, 35.27845], [61.12831, 35.09938], [61.06926, 34.82139], [61.00197, 34.70631], [60.99922, 34.63064], [60.72316, 34.52857], [60.91321, 34.30411], [60.66502, 34.31539], [60.50209, 34.13992], [60.5838, 33.80793], [60.5485, 33.73422], [60.57762, 33.59772], [60.69573, 33.56054], [60.91133, 33.55596], [60.88908, 33.50219], [60.56485, 33.12944], [60.86191, 32.22565], [60.84541, 31.49561], [61.70929, 31.37391], [61.80569, 31.16167], [61.80957, 31.12576], [61.83257, 31.0452], [61.8335, 30.97669], [61.78268, 30.92724], [61.80829, 30.84224], [60.87231, 29.86514], [62.47751, 29.40782], [63.5876, 29.50456], [64.12966, 29.39157], [64.19796, 29.50407], [64.62116, 29.58903], [65.04005, 29.53957], [66.24175, 29.85181], [66.36042, 29.9583], [66.23609, 30.06321], [66.34869, 30.404], [66.28413, 30.57001], [66.39194, 30.9408], [66.42645, 30.95309], [66.58175, 30.97532], [66.68166, 31.07597], [66.72561, 31.20526], [66.83273, 31.26867], [67.04147, 31.31561], [67.03323, 31.24519], [67.29964, 31.19586], [67.78854, 31.33203], [67.7748, 31.4188], [67.62374, 31.40473], [67.58323, 31.52772], [67.72056, 31.52304], [67.86887, 31.63536], [68.00071, 31.6564], [68.1655, 31.82691], [68.25614, 31.80357], [68.27605, 31.75863], [68.44222, 31.76446], [68.57475, 31.83158], [68.6956, 31.75687], [68.79997, 31.61665], [68.91078, 31.59687], [68.95995, 31.64822], [69.00939, 31.62249], [69.11514, 31.70782], [69.20577, 31.85957], [69.3225, 31.93186], [69.27032, 32.14141], [69.27932, 32.29119], [69.23599, 32.45946], [69.2868, 32.53938], [69.38155, 32.56601], [69.44747, 32.6678], [69.43649, 32.7302], [69.38018, 32.76601], [69.47082, 32.85834], [69.5436, 32.8768], [69.49854, 32.88843], [69.49004, 33.01509], [69.57656, 33.09911], [69.71526, 33.09911], [69.79766, 33.13247], [69.85259, 33.09451], [70.02563, 33.14282], [70.07369, 33.22557], [70.13686, 33.21064], [70.32775, 33.34496], [70.17062, 33.53535], [70.20141, 33.64387], [70.14785, 33.6553], [70.14236, 33.71701], [70.00503, 33.73528], [69.85671, 33.93719], [69.87307, 33.9689], [69.90203, 34.04194], [70.54336, 33.9463], [70.88119, 33.97933], [71.07345, 34.06242], [71.06933, 34.10564], [71.09307, 34.11961], [71.09453, 34.13524], [71.13078, 34.16503], [71.12815, 34.26619], [71.17662, 34.36769], [71.02401, 34.44835], [71.0089, 34.54568], [71.11602, 34.63047], [71.08718, 34.69034], [71.28356, 34.80882], [71.29472, 34.87728], [71.50329, 34.97328], [71.49917, 35.00478], [71.55273, 35.02615], [71.52938, 35.09023], [71.67495, 35.21262], [71.5541, 35.28776], [71.54294, 35.31037], [71.65435, 35.4479], [71.49917, 35.6267], [71.55273, 35.71483], [71.37969, 35.95865], [71.19505, 36.04134], [71.60491, 36.39429], [71.80267, 36.49924], [72.18135, 36.71838], [72.6323, 36.84601], [73.82685, 36.91421], [74.04856, 36.82648], [74.43389, 37.00977], [74.53739, 36.96224], [74.56453, 37.03023], [74.49981, 37.24518], [74.80605, 37.21565], [74.88887, 37.23275], [74.8294, 37.3435], [74.68383, 37.3948], [74.56161, 37.37734], [74.41055, 37.3948], [74.23339, 37.41116], [74.20308, 37.34208], [73.8564, 37.26158], [73.82552, 37.22659], [73.64974, 37.23643], [73.61129, 37.27469], [73.76647, 37.33913], [73.77197, 37.4417], [73.29633, 37.46495], [73.06884, 37.31729], [72.79693, 37.22222], [72.66381, 37.02014], [72.54095, 37.00007], [72.31676, 36.98115], [71.83229, 36.68084], [71.67083, 36.67346], [71.57195, 36.74943], [71.51502, 36.89128], [71.48481, 36.93218], [71.46923, 36.99925], [71.45578, 37.03094], [71.43097, 37.05855], [71.44127, 37.11856], [71.4494, 37.18137], [71.4555, 37.21418], [71.47386, 37.2269], [71.48339, 37.23937], [71.4824, 37.24921], [71.48536, 37.26017], [71.50674, 37.31502], [71.49821, 37.31975], [71.4862, 37.33405], [71.47685, 37.40281], [71.49612, 37.4279], [71.5256, 37.47971], [71.50616, 37.50733], [71.49693, 37.53527], [71.5065, 37.60912], [71.51972, 37.61945], [71.54186, 37.69691], [71.55234, 37.73209], [71.53053, 37.76534], [71.54324, 37.77104], [71.55752, 37.78677], [71.59255, 37.79956], [71.58843, 37.92425], [71.51565, 37.95349], [71.32871, 37.88564], [71.296, 37.93403], [71.2809, 37.91995], [71.24969, 37.93031], [71.27278, 37.96496], [71.27622, 37.99946], [71.28922, 38.01272], [71.29878, 38.04429], [71.36444, 38.15358], [71.37803, 38.25641], [71.33869, 38.27335], [71.33114, 38.30339], [71.21291, 38.32797], [71.1451, 38.40106], [71.10957, 38.40671], [71.10592, 38.42077], [71.09542, 38.42517], [71.0556, 38.40176], [71.03545, 38.44779], [70.98693, 38.48862], [70.92728, 38.43021], [70.88719, 38.46826], [70.84376, 38.44688], [70.82538, 38.45394], [70.81697, 38.44507], [70.80521, 38.44447], [70.79766, 38.44944], [70.78702, 38.45031], [70.78581, 38.45502], [70.77132, 38.45548], [70.75455, 38.4252], [70.72485, 38.4131], [70.69807, 38.41861], [70.67438, 38.40597], [70.6761, 38.39144], [70.69189, 38.37031], [70.64966, 38.34999], [70.61526, 38.34774]]]]
23027           }
23028         }, {
23029           type: "Feature",
23030           properties: {
23031             iso1A2: "AG",
23032             iso1A3: "ATG",
23033             iso1N3: "028",
23034             wikidata: "Q781",
23035             nameEn: "Antigua and Barbuda",
23036             groups: ["029", "003", "419", "019", "UN"],
23037             driveSide: "left",
23038             roadSpeedUnit: "mph",
23039             callingCodes: ["1 268"]
23040           },
23041           geometry: {
23042             type: "MultiPolygon",
23043             coordinates: [[[[-61.66959, 18.6782], [-62.58307, 16.68909], [-62.1023, 16.97277], [-61.23098, 16.62484], [-61.66959, 18.6782]]]]
23044           }
23045         }, {
23046           type: "Feature",
23047           properties: {
23048             iso1A2: "AI",
23049             iso1A3: "AIA",
23050             iso1N3: "660",
23051             wikidata: "Q25228",
23052             nameEn: "Anguilla",
23053             country: "GB",
23054             groups: ["BOTS", "029", "003", "419", "019", "UN"],
23055             driveSide: "left",
23056             roadSpeedUnit: "mph",
23057             callingCodes: ["1 264"]
23058           },
23059           geometry: {
23060             type: "MultiPolygon",
23061             coordinates: [[[[-63.79029, 19.11219], [-63.35989, 18.06012], [-62.62718, 18.26185], [-63.79029, 19.11219]]]]
23062           }
23063         }, {
23064           type: "Feature",
23065           properties: {
23066             iso1A2: "AL",
23067             iso1A3: "ALB",
23068             iso1N3: "008",
23069             wikidata: "Q222",
23070             nameEn: "Albania",
23071             groups: ["039", "150", "UN"],
23072             callingCodes: ["355"]
23073           },
23074           geometry: {
23075             type: "MultiPolygon",
23076             coordinates: [[[[20.07761, 42.55582], [20.01834, 42.54622], [20.00842, 42.5109], [19.9324, 42.51699], [19.82333, 42.46581], [19.76549, 42.50237], [19.74731, 42.57422], [19.77375, 42.58517], [19.73244, 42.66299], [19.65972, 42.62774], [19.4836, 42.40831], [19.42352, 42.36546], [19.42, 42.33019], [19.28623, 42.17745], [19.40687, 42.10024], [19.37548, 42.06835], [19.36867, 42.02564], [19.37691, 41.96977], [19.34601, 41.95675], [19.33812, 41.90669], [19.37451, 41.8842], [19.37597, 41.84849], [19.26406, 41.74971], [19.0384, 40.35325], [19.95905, 39.82857], [19.97622, 39.78684], [19.92466, 39.69533], [19.98042, 39.6504], [20.00957, 39.69227], [20.05189, 39.69112], [20.12956, 39.65805], [20.15988, 39.652], [20.22376, 39.64532], [20.22707, 39.67459], [20.27412, 39.69884], [20.31961, 39.72799], [20.29152, 39.80421], [20.30804, 39.81563], [20.38572, 39.78516], [20.41475, 39.81437], [20.41546, 39.82832], [20.31135, 39.99438], [20.37911, 39.99058], [20.42373, 40.06777], [20.48487, 40.06271], [20.51297, 40.08168], [20.55593, 40.06524], [20.61081, 40.07866], [20.62566, 40.0897], [20.67162, 40.09433], [20.71789, 40.27739], [20.78234, 40.35803], [20.7906, 40.42726], [20.83688, 40.47882], [20.94925, 40.46625], [20.96908, 40.51526], [21.03932, 40.56299], [21.05833, 40.66586], [20.98134, 40.76046], [20.95752, 40.76982], [20.98396, 40.79109], [20.97887, 40.85475], [20.97693, 40.90103], [20.94305, 40.92399], [20.83671, 40.92752], [20.81567, 40.89662], [20.73504, 40.9081], [20.71634, 40.91781], [20.65558, 41.08009], [20.63454, 41.0889], [20.59832, 41.09066], [20.58546, 41.11179], [20.59715, 41.13644], [20.51068, 41.2323], [20.49432, 41.33679], [20.52119, 41.34381], [20.55976, 41.4087], [20.51301, 41.442], [20.49039, 41.49277], [20.45331, 41.51436], [20.45809, 41.5549], [20.52103, 41.56473], [20.55508, 41.58113], [20.51769, 41.65975], [20.52937, 41.69292], [20.51301, 41.72433], [20.53405, 41.78099], [20.57144, 41.7897], [20.55976, 41.87068], [20.59524, 41.8818], [20.57946, 41.91593], [20.63069, 41.94913], [20.59434, 42.03879], [20.55633, 42.08173], [20.56955, 42.12097], [20.48857, 42.25444], [20.3819, 42.3029], [20.34479, 42.32656], [20.24399, 42.32168], [20.21797, 42.41237], [20.17127, 42.50469], [20.07761, 42.55582]]]]
23077           }
23078         }, {
23079           type: "Feature",
23080           properties: {
23081             iso1A2: "AM",
23082             iso1A3: "ARM",
23083             iso1N3: "051",
23084             wikidata: "Q399",
23085             nameEn: "Armenia",
23086             groups: ["145", "142", "UN"],
23087             callingCodes: ["374"]
23088           },
23089           geometry: {
23090             type: "MultiPolygon",
23091             coordinates: [[[[45.0133, 41.29747], [44.93493, 41.25685], [44.81437, 41.30371], [44.80053, 41.25949], [44.81749, 41.23488], [44.84358, 41.23088], [44.89911, 41.21366], [44.87887, 41.20195], [44.82084, 41.21513], [44.72814, 41.20338], [44.61462, 41.24018], [44.59322, 41.1933], [44.46791, 41.18204], [44.34417, 41.2382], [44.34337, 41.20312], [44.32139, 41.2079], [44.18148, 41.24644], [44.16591, 41.19141], [43.84835, 41.16329], [43.74717, 41.1117], [43.67712, 41.13398], [43.4717, 41.12611], [43.44984, 41.0988], [43.47319, 41.02251], [43.58683, 40.98961], [43.67712, 40.93084], [43.67712, 40.84846], [43.74872, 40.7365], [43.7425, 40.66805], [43.63664, 40.54159], [43.54791, 40.47413], [43.60862, 40.43267], [43.59928, 40.34019], [43.71136, 40.16673], [43.65221, 40.14889], [43.65688, 40.11199], [43.92307, 40.01787], [44.1057, 40.03555], [44.1778, 40.02845], [44.26973, 40.04866], [44.46635, 39.97733], [44.61845, 39.8281], [44.75779, 39.7148], [44.88354, 39.74432], [44.92869, 39.72157], [45.06604, 39.79277], [45.18554, 39.67846], [45.17464, 39.58614], [45.21784, 39.58074], [45.23535, 39.61373], [45.30385, 39.61373], [45.29606, 39.57654], [45.46992, 39.49888], [45.70547, 39.60174], [45.80804, 39.56716], [45.83, 39.46487], [45.79225, 39.3695], [45.99774, 39.28931], [46.02303, 39.09978], [46.06973, 39.0744], [46.14785, 38.84206], [46.20601, 38.85262], [46.34059, 38.92076], [46.53497, 38.86548], [46.51805, 38.94982], [46.54296, 39.07078], [46.44022, 39.19636], [46.52584, 39.18912], [46.54141, 39.15895], [46.58032, 39.21204], [46.63481, 39.23013], [46.56476, 39.24942], [46.50093, 39.33736], [46.43244, 39.35181], [46.37795, 39.42039], [46.4013, 39.45405], [46.53051, 39.47809], [46.51027, 39.52373], [46.57721, 39.54414], [46.57098, 39.56694], [46.52117, 39.58734], [46.42465, 39.57534], [46.40286, 39.63651], [46.18493, 39.60533], [45.96543, 39.78859], [45.82533, 39.82925], [45.7833, 39.9475], [45.60895, 39.97733], [45.59806, 40.0131], [45.78642, 40.03218], [45.83779, 39.98925], [45.97944, 40.181], [45.95609, 40.27846], [45.65098, 40.37696], [45.42994, 40.53804], [45.45484, 40.57707], [45.35366, 40.65979], [45.4206, 40.7424], [45.55914, 40.78366], [45.60584, 40.87436], [45.40814, 40.97904], [45.44083, 41.01663], [45.39725, 41.02603], [45.35677, 40.99784], [45.28859, 41.03757], [45.26162, 41.0228], [45.25897, 41.0027], [45.1994, 41.04518], [45.16493, 41.05068], [45.1634, 41.08082], [45.1313, 41.09369], [45.12923, 41.06059], [45.06784, 41.05379], [45.08028, 41.10917], [45.19942, 41.13299], [45.1969, 41.168], [45.11811, 41.19967], [45.05201, 41.19211], [45.02932, 41.2101], [45.05497, 41.2464], [45.0133, 41.29747]], [[45.21324, 40.9817], [45.21219, 40.99001], [45.20518, 40.99348], [45.19312, 40.98998], [45.18382, 41.0066], [45.20625, 41.01484], [45.23487, 41.00226], [45.23095, 40.97828], [45.21324, 40.9817]], [[45.00864, 41.03411], [44.9903, 41.05657], [44.96031, 41.06345], [44.95383, 41.07553], [44.97169, 41.09176], [45.00864, 41.09407], [45.03406, 41.07931], [45.04517, 41.06653], [45.03792, 41.03938], [45.00864, 41.03411]]], [[[45.50279, 40.58424], [45.56071, 40.64765], [45.51825, 40.67382], [45.47927, 40.65023], [45.50279, 40.58424]]]]
23092           }
23093         }, {
23094           type: "Feature",
23095           properties: {
23096             iso1A2: "AO",
23097             iso1A3: "AGO",
23098             iso1N3: "024",
23099             wikidata: "Q916",
23100             nameEn: "Angola",
23101             groups: ["017", "202", "002", "UN"],
23102             callingCodes: ["244"]
23103           },
23104           geometry: {
23105             type: "MultiPolygon",
23106             coordinates: [[[[16.55507, -5.85631], [13.04371, -5.87078], [12.42245, -6.07585], [11.95767, -5.94705], [12.20376, -5.76338], [12.26557, -5.74031], [12.52318, -5.74353], [12.52301, -5.17481], [12.53599, -5.1618], [12.53586, -5.14658], [12.51589, -5.1332], [12.49815, -5.14058], [12.46297, -5.09408], [12.60251, -5.01715], [12.63465, -4.94632], [12.70868, -4.95505], [12.8733, -4.74346], [13.11195, -4.67745], [13.09648, -4.63739], [12.91489, -4.47907], [12.87096, -4.40315], [12.76844, -4.38709], [12.64835, -4.55937], [12.40964, -4.60609], [12.32324, -4.78415], [12.25587, -4.79437], [12.20901, -4.75642], [12.16068, -4.90089], [12.00924, -5.02627], [11.50888, -5.33417], [10.5065, -17.25284], [11.75063, -17.25013], [12.07076, -17.15165], [12.52111, -17.24495], [12.97145, -16.98567], [13.36212, -16.98048], [13.95896, -17.43141], [14.28743, -17.38814], [18.39229, -17.38927], [18.84226, -17.80375], [21.14283, -17.94318], [21.42741, -18.02787], [23.47474, -17.62877], [23.20038, -17.47563], [22.17217, -16.50269], [22.00323, -16.18028], [21.97988, -13.00148], [24.03339, -12.99091], [23.90937, -12.844], [24.06672, -12.29058], [23.98804, -12.13149], [24.02603, -11.15368], [24.00027, -10.89356], [23.86868, -11.02856], [23.45631, -10.946], [23.16602, -11.10577], [22.54205, -11.05784], [22.25951, -11.24911], [22.17954, -10.85884], [22.32604, -10.76291], [22.19039, -9.94628], [21.84856, -9.59871], [21.79824, -7.29628], [20.56263, -7.28566], [20.61689, -6.90876], [20.31846, -6.91953], [20.30218, -6.98955], [19.5469, -7.00195], [19.33698, -7.99743], [18.33635, -8.00126], [17.5828, -8.13784], [16.96282, -7.21787], [16.55507, -5.85631]]]]
23107           }
23108         }, {
23109           type: "Feature",
23110           properties: {
23111             iso1A2: "AQ",
23112             iso1A3: "ATA",
23113             iso1N3: "010",
23114             wikidata: "Q51",
23115             nameEn: "Antarctica",
23116             level: "region",
23117             callingCodes: ["672"]
23118           },
23119           geometry: {
23120             type: "MultiPolygon",
23121             coordinates: [[[[180, -60], [-180, -60], [-180, -90], [180, -90], [180, -60]]]]
23122           }
23123         }, {
23124           type: "Feature",
23125           properties: {
23126             iso1A2: "AR",
23127             iso1A3: "ARG",
23128             iso1N3: "032",
23129             wikidata: "Q414",
23130             nameEn: "Argentina",
23131             aliases: ["RA"],
23132             groups: ["005", "419", "019", "UN"],
23133             callingCodes: ["54"]
23134           },
23135           geometry: {
23136             type: "MultiPolygon",
23137             coordinates: [[[[-72.31343, -50.58411], [-72.33873, -51.59954], [-71.99889, -51.98018], [-69.97824, -52.00845], [-68.41683, -52.33516], [-68.60702, -52.65781], [-68.60733, -54.9125], [-68.01394, -54.8753], [-67.46182, -54.92205], [-67.11046, -54.94199], [-66.07313, -55.19618], [-63.67376, -55.11859], [-54.78916, -36.21945], [-57.83001, -34.69099], [-58.34425, -34.15035], [-58.44442, -33.84033], [-58.40475, -33.11777], [-58.1224, -32.98842], [-58.22362, -32.52416], [-58.10036, -32.25338], [-58.20252, -31.86966], [-58.00076, -31.65016], [-58.0023, -31.53084], [-58.07569, -31.44916], [-57.98127, -31.3872], [-57.9908, -31.34924], [-57.86729, -31.06352], [-57.89476, -30.95994], [-57.8024, -30.77193], [-57.89115, -30.49572], [-57.64859, -30.35095], [-57.61478, -30.25165], [-57.65132, -30.19229], [-57.09386, -29.74211], [-56.81251, -29.48154], [-56.62789, -29.18073], [-56.57295, -29.11357], [-56.54171, -29.11447], [-56.05265, -28.62651], [-56.00458, -28.60421], [-56.01729, -28.51223], [-55.65418, -28.18304], [-55.6262, -28.17124], [-55.33303, -27.94661], [-55.16872, -27.86224], [-55.1349, -27.89759], [-54.90805, -27.73149], [-54.90159, -27.63132], [-54.67657, -27.57214], [-54.50416, -27.48232], [-54.41888, -27.40882], [-54.19268, -27.30751], [-54.19062, -27.27639], [-54.15978, -27.2889], [-53.80144, -27.09844], [-53.73372, -26.6131], [-53.68269, -26.33359], [-53.64505, -26.28089], [-53.64186, -26.25976], [-53.64632, -26.24798], [-53.63881, -26.25075], [-53.63739, -26.2496], [-53.65237, -26.23289], [-53.65018, -26.19501], [-53.73968, -26.10012], [-53.73391, -26.07006], [-53.7264, -26.0664], [-53.73086, -26.05842], [-53.73511, -26.04211], [-53.83691, -25.94849], [-53.90831, -25.55513], [-54.52926, -25.62846], [-54.5502, -25.58915], [-54.59398, -25.59224], [-54.62063, -25.91213], [-54.60664, -25.9691], [-54.67359, -25.98607], [-54.69333, -26.37705], [-54.70732, -26.45099], [-54.80868, -26.55669], [-55.00584, -26.78754], [-55.06351, -26.80195], [-55.16948, -26.96068], [-55.25243, -26.93808], [-55.39611, -26.97679], [-55.62322, -27.1941], [-55.59094, -27.32444], [-55.74475, -27.44485], [-55.89195, -27.3467], [-56.18313, -27.29851], [-56.85337, -27.5165], [-58.04205, -27.2387], [-58.59549, -27.29973], [-58.65321, -27.14028], [-58.3198, -26.83443], [-58.1188, -26.16704], [-57.87176, -25.93604], [-57.57431, -25.47269], [-57.80821, -25.13863], [-58.25492, -24.92528], [-58.33055, -24.97099], [-59.33886, -24.49935], [-59.45482, -24.34787], [-60.03367, -24.00701], [-60.28163, -24.04436], [-60.99754, -23.80934], [-61.0782, -23.62932], [-61.9756, -23.0507], [-62.22768, -22.55807], [-62.51761, -22.37684], [-62.64455, -22.25091], [-62.8078, -22.12534], [-62.81124, -21.9987], [-63.66482, -21.99918], [-63.68113, -22.0544], [-63.70963, -21.99934], [-63.93287, -21.99934], [-64.22918, -22.55807], [-64.31489, -22.88824], [-64.35108, -22.73282], [-64.4176, -22.67692], [-64.58888, -22.25035], [-64.67174, -22.18957], [-64.90014, -22.12136], [-64.99524, -22.08255], [-65.47435, -22.08908], [-65.57743, -22.07675], [-65.58694, -22.09794], [-65.61166, -22.09504], [-65.7467, -22.10105], [-65.9261, -21.93335], [-66.04832, -21.9187], [-66.03836, -21.84829], [-66.24077, -21.77837], [-66.29714, -22.08741], [-66.7298, -22.23644], [-67.18382, -22.81525], [-66.99632, -22.99839], [-67.33563, -24.04237], [-68.24825, -24.42596], [-68.56909, -24.69831], [-68.38372, -25.08636], [-68.57622, -25.32505], [-68.38372, -26.15353], [-68.56909, -26.28146], [-68.59048, -26.49861], [-68.27677, -26.90626], [-68.43363, -27.08414], [-68.77586, -27.16029], [-69.22504, -27.95042], [-69.66709, -28.44055], [-69.80969, -29.07185], [-69.99507, -29.28351], [-69.8596, -30.26131], [-70.14479, -30.36595], [-70.55832, -31.51559], [-69.88099, -33.34489], [-69.87386, -34.13344], [-70.49416, -35.24145], [-70.38008, -36.02375], [-70.95047, -36.4321], [-71.24279, -37.20264], [-70.89532, -38.6923], [-71.37826, -38.91474], [-71.92726, -40.72714], [-71.74901, -42.11711], [-72.15541, -42.15941], [-72.14828, -42.85321], [-71.64206, -43.64774], [-71.81318, -44.38097], [-71.16436, -44.46244], [-71.26418, -44.75684], [-72.06985, -44.81756], [-71.35687, -45.22075], [-71.75614, -45.61611], [-71.68577, -46.55385], [-71.94152, -47.13595], [-72.50478, -47.80586], [-72.27662, -48.28727], [-72.54042, -48.52392], [-72.56894, -48.81116], [-73.09655, -49.14342], [-73.45156, -49.79461], [-73.55259, -49.92488], [-73.15765, -50.78337], [-72.31343, -50.58411]]]]
23138           }
23139         }, {
23140           type: "Feature",
23141           properties: {
23142             iso1A2: "AS",
23143             iso1A3: "ASM",
23144             iso1N3: "016",
23145             wikidata: "Q16641",
23146             nameEn: "American Samoa",
23147             aliases: ["US-AS"],
23148             country: "US",
23149             groups: ["Q1352230", "061", "009", "UN"],
23150             roadSpeedUnit: "mph",
23151             roadHeightUnit: "ft",
23152             callingCodes: ["1 684"]
23153           },
23154           geometry: {
23155             type: "MultiPolygon",
23156             coordinates: [[[[-171.39864, -10.21587], [-170.99605, -15.1275], [-166.32598, -15.26169], [-171.39864, -10.21587]]]]
23157           }
23158         }, {
23159           type: "Feature",
23160           properties: {
23161             iso1A2: "AT",
23162             iso1A3: "AUT",
23163             iso1N3: "040",
23164             wikidata: "Q40",
23165             nameEn: "Austria",
23166             groups: ["EU", "155", "150", "UN"],
23167             callingCodes: ["43"]
23168           },
23169           geometry: {
23170             type: "MultiPolygon",
23171             coordinates: [[[[15.34823, 48.98444], [15.28305, 48.98831], [15.26177, 48.95766], [15.16358, 48.94278], [15.15534, 48.99056], [14.99878, 49.01444], [14.97612, 48.96983], [14.98917, 48.90082], [14.95072, 48.79101], [14.98032, 48.77959], [14.9782, 48.7766], [14.98112, 48.77524], [14.9758, 48.76857], [14.95641, 48.75915], [14.94773, 48.76268], [14.81545, 48.7874], [14.80821, 48.77711], [14.80584, 48.73489], [14.72756, 48.69502], [14.71794, 48.59794], [14.66762, 48.58215], [14.60808, 48.62881], [14.56139, 48.60429], [14.4587, 48.64695], [14.43076, 48.58855], [14.33909, 48.55852], [14.20691, 48.5898], [14.09104, 48.5943], [14.01482, 48.63788], [14.06151, 48.66873], [13.84023, 48.76988], [13.82266, 48.75544], [13.81863, 48.73257], [13.79337, 48.71375], [13.81791, 48.69832], [13.81283, 48.68426], [13.81901, 48.6761], [13.82609, 48.62345], [13.80038, 48.59487], [13.80519, 48.58026], [13.76921, 48.55324], [13.7513, 48.5624], [13.74816, 48.53058], [13.72802, 48.51208], [13.66113, 48.53558], [13.65186, 48.55092], [13.62508, 48.55501], [13.59705, 48.57013], [13.57535, 48.55912], [13.51291, 48.59023], [13.50131, 48.58091], [13.50663, 48.57506], [13.46967, 48.55157], [13.45214, 48.56472], [13.43695, 48.55776], [13.45727, 48.51092], [13.42527, 48.45711], [13.43929, 48.43386], [13.40709, 48.37292], [13.30897, 48.31575], [13.26039, 48.29422], [13.18093, 48.29577], [13.126, 48.27867], [13.0851, 48.27711], [13.02083, 48.25689], [12.95306, 48.20629], [12.87126, 48.20318], [12.84475, 48.16556], [12.836, 48.1647], [12.8362, 48.15876], [12.82673, 48.15245], [12.80676, 48.14979], [12.78595, 48.12445], [12.7617, 48.12796], [12.74973, 48.10885], [12.76141, 48.07373], [12.8549, 48.01122], [12.87476, 47.96195], [12.91683, 47.95647], [12.9211, 47.95135], [12.91985, 47.94069], [12.92668, 47.93879], [12.93419, 47.94063], [12.93642, 47.94436], [12.93886, 47.94046], [12.94163, 47.92927], [13.00588, 47.84374], [12.98543, 47.82896], [12.96311, 47.79957], [12.93202, 47.77302], [12.94371, 47.76281], [12.9353, 47.74788], [12.91711, 47.74026], [12.90274, 47.72513], [12.91333, 47.7178], [12.92969, 47.71094], [12.98578, 47.7078], [13.01382, 47.72116], [13.07692, 47.68814], [13.09562, 47.63304], [13.06407, 47.60075], [13.06641, 47.58577], [13.04537, 47.58183], [13.05355, 47.56291], [13.03252, 47.53373], [13.04537, 47.49426], [12.9998, 47.46267], [12.98344, 47.48716], [12.9624, 47.47452], [12.85256, 47.52741], [12.84672, 47.54556], [12.80699, 47.54477], [12.77427, 47.58025], [12.82101, 47.61493], [12.76492, 47.64485], [12.77777, 47.66689], [12.7357, 47.6787], [12.6071, 47.6741], [12.57438, 47.63238], [12.53816, 47.63553], [12.50076, 47.62293], [12.44117, 47.6741], [12.43883, 47.6977], [12.37222, 47.68433], [12.336, 47.69534], [12.27991, 47.68827], [12.26004, 47.67725], [12.24017, 47.69534], [12.26238, 47.73544], [12.2542, 47.7433], [12.22571, 47.71776], [12.18303, 47.70065], [12.16217, 47.70105], [12.16769, 47.68167], [12.18347, 47.66663], [12.18507, 47.65984], [12.19895, 47.64085], [12.20801, 47.61082], [12.20398, 47.60667], [12.18568, 47.6049], [12.17737, 47.60121], [12.18145, 47.61019], [12.17824, 47.61506], [12.13734, 47.60639], [12.05788, 47.61742], [12.02282, 47.61033], [12.0088, 47.62451], [11.85572, 47.60166], [11.84052, 47.58354], [11.63934, 47.59202], [11.60681, 47.57881], [11.58811, 47.55515], [11.58578, 47.52281], [11.52618, 47.50939], [11.4362, 47.51413], [11.38128, 47.47465], [11.4175, 47.44621], [11.33804, 47.44937], [11.29597, 47.42566], [11.27844, 47.39956], [11.22002, 47.3964], [11.25157, 47.43277], [11.20482, 47.43198], [11.12536, 47.41222], [11.11835, 47.39719], [10.97111, 47.39561], [10.97111, 47.41617], [10.98513, 47.42882], [10.92437, 47.46991], [10.93839, 47.48018], [10.90918, 47.48571], [10.87061, 47.4786], [10.86945, 47.5015], [10.91268, 47.51334], [10.88814, 47.53701], [10.77596, 47.51729], [10.7596, 47.53228], [10.6965, 47.54253], [10.68832, 47.55752], [10.63456, 47.5591], [10.60337, 47.56755], [10.56912, 47.53584], [10.48849, 47.54057], [10.47329, 47.58552], [10.43473, 47.58394], [10.44992, 47.5524], [10.4324, 47.50111], [10.44291, 47.48453], [10.46278, 47.47901], [10.47446, 47.43318], [10.4359, 47.41183], [10.4324, 47.38494], [10.39851, 47.37623], [10.33424, 47.30813], [10.23257, 47.27088], [10.17531, 47.27167], [10.17648, 47.29149], [10.2147, 47.31014], [10.19998, 47.32832], [10.23757, 47.37609], [10.22774, 47.38904], [10.2127, 47.38019], [10.17648, 47.38889], [10.16362, 47.36674], [10.11805, 47.37228], [10.09819, 47.35724], [10.06897, 47.40709], [10.1052, 47.4316], [10.09001, 47.46005], [10.07131, 47.45531], [10.03859, 47.48927], [10.00003, 47.48216], [9.96029, 47.53899], [9.92407, 47.53111], [9.87733, 47.54688], [9.87499, 47.52953], [9.8189, 47.54688], [9.82591, 47.58158], [9.80254, 47.59419], [9.76748, 47.5934], [9.72736, 47.53457], [9.55125, 47.53629], [9.56312, 47.49495], [9.58208, 47.48344], [9.59482, 47.46305], [9.60205, 47.46165], [9.60484, 47.46358], [9.60841, 47.47178], [9.62158, 47.45858], [9.62475, 47.45685], [9.6423, 47.45599], [9.65728, 47.45383], [9.65863, 47.44847], [9.64483, 47.43842], [9.6446, 47.43233], [9.65043, 47.41937], [9.65136, 47.40504], [9.6629, 47.39591], [9.67334, 47.39191], [9.67445, 47.38429], [9.6711, 47.37824], [9.66243, 47.37136], [9.65427, 47.36824], [9.62476, 47.36639], [9.59978, 47.34671], [9.58513, 47.31334], [9.55857, 47.29919], [9.54773, 47.2809], [9.53116, 47.27029], [9.56766, 47.24281], [9.55176, 47.22585], [9.56981, 47.21926], [9.58264, 47.20673], [9.56539, 47.17124], [9.62623, 47.14685], [9.63395, 47.08443], [9.61216, 47.07732], [9.60717, 47.06091], [9.87935, 47.01337], [9.88266, 46.93343], [9.98058, 46.91434], [10.10715, 46.84296], [10.22675, 46.86942], [10.24128, 46.93147], [10.30031, 46.92093], [10.36933, 47.00212], [10.48376, 46.93891], [10.47197, 46.85698], [10.54783, 46.84505], [10.66405, 46.87614], [10.75753, 46.82258], [10.72974, 46.78972], [11.00764, 46.76896], [11.10618, 46.92966], [11.33355, 46.99862], [11.50739, 47.00644], [11.74789, 46.98484], [12.19254, 47.09331], [12.21781, 47.03996], [12.11675, 47.01241], [12.2006, 46.88854], [12.27591, 46.88651], [12.38708, 46.71529], [12.59992, 46.6595], [12.94445, 46.60401], [13.27627, 46.56059], [13.64088, 46.53438], [13.7148, 46.5222], [13.89837, 46.52331], [14.00422, 46.48474], [14.04002, 46.49117], [14.12097, 46.47724], [14.15989, 46.43327], [14.28326, 46.44315], [14.314, 46.43327], [14.42608, 46.44614], [14.45877, 46.41717], [14.52176, 46.42617], [14.56463, 46.37208], [14.5942, 46.43434], [14.66892, 46.44936], [14.72185, 46.49974], [14.81836, 46.51046], [14.83549, 46.56614], [14.86419, 46.59411], [14.87129, 46.61], [14.92283, 46.60848], [14.96002, 46.63459], [14.98024, 46.6009], [15.01451, 46.641], [15.14215, 46.66131], [15.23711, 46.63994], [15.41235, 46.65556], [15.45514, 46.63697], [15.46906, 46.61321], [15.54431, 46.6312], [15.55333, 46.64988], [15.54533, 46.66985], [15.59826, 46.68908], [15.62317, 46.67947], [15.63255, 46.68069], [15.6365, 46.6894], [15.6543, 46.69228], [15.6543, 46.70616], [15.67411, 46.70735], [15.69523, 46.69823], [15.72279, 46.69548], [15.73823, 46.70011], [15.76771, 46.69863], [15.78518, 46.70712], [15.8162, 46.71897], [15.87691, 46.7211], [15.94864, 46.68769], [15.98512, 46.68463], [15.99988, 46.67947], [16.04036, 46.6549], [16.04347, 46.68694], [16.02808, 46.71094], [15.99769, 46.7266], [15.98432, 46.74991], [15.99126, 46.78199], [15.99054, 46.82772], [16.05786, 46.83927], [16.10983, 46.867], [16.19904, 46.94134], [16.22403, 46.939], [16.27594, 46.9643], [16.28202, 47.00159], [16.51369, 47.00084], [16.43936, 47.03548], [16.52176, 47.05747], [16.46134, 47.09395], [16.52863, 47.13974], [16.44932, 47.14418], [16.46442, 47.16845], [16.4523, 47.18812], [16.42801, 47.18422], [16.41739, 47.20649], [16.43663, 47.21127], [16.44142, 47.25079], [16.47782, 47.25918], [16.45104, 47.41181], [16.49908, 47.39416], [16.52414, 47.41007], [16.57152, 47.40868], [16.6718, 47.46139], [16.64821, 47.50155], [16.71059, 47.52692], [16.64193, 47.63114], [16.58699, 47.61772], [16.4222, 47.66537], [16.55129, 47.72268], [16.53514, 47.73837], [16.54779, 47.75074], [16.61183, 47.76171], [16.65679, 47.74197], [16.72089, 47.73469], [16.7511, 47.67878], [16.82938, 47.68432], [16.86509, 47.72268], [16.87538, 47.68895], [17.08893, 47.70928], [17.05048, 47.79377], [17.07039, 47.81129], [17.00997, 47.86245], [17.08275, 47.87719], [17.11022, 47.92461], [17.09786, 47.97336], [17.16001, 48.00636], [17.07039, 48.0317], [17.09168, 48.09366], [17.05735, 48.14179], [17.02919, 48.13996], [16.97701, 48.17385], [16.89461, 48.31332], [16.90903, 48.32519], [16.84243, 48.35258], [16.83317, 48.38138], [16.83588, 48.3844], [16.8497, 48.38321], [16.85204, 48.44968], [16.94611, 48.53614], [16.93955, 48.60371], [16.90354, 48.71541], [16.79779, 48.70998], [16.71883, 48.73806], [16.68518, 48.7281], [16.67008, 48.77699], [16.46134, 48.80865], [16.40915, 48.74576], [16.37345, 48.729], [16.06034, 48.75436], [15.84404, 48.86921], [15.78087, 48.87644], [15.75341, 48.8516], [15.6921, 48.85973], [15.61622, 48.89541], [15.51357, 48.91549], [15.48027, 48.94481], [15.34823, 48.98444]]]]
23172           }
23173         }, {
23174           type: "Feature",
23175           properties: {
23176             iso1A2: "AU",
23177             iso1A3: "AUS",
23178             iso1N3: "036",
23179             wikidata: "Q408",
23180             nameEn: "Australia"
23181           },
23182           geometry: null
23183         }, {
23184           type: "Feature",
23185           properties: {
23186             iso1A2: "AW",
23187             iso1A3: "ABW",
23188             iso1N3: "533",
23189             wikidata: "Q21203",
23190             nameEn: "Aruba",
23191             aliases: ["NL-AW"],
23192             country: "NL",
23193             groups: ["Q1451600", "029", "003", "419", "019", "UN"],
23194             callingCodes: ["297"]
23195           },
23196           geometry: {
23197             type: "MultiPolygon",
23198             coordinates: [[[[-70.00823, 12.98375], [-70.35625, 12.58277], [-69.60231, 12.17], [-70.00823, 12.98375]]]]
23199           }
23200         }, {
23201           type: "Feature",
23202           properties: {
23203             iso1A2: "AX",
23204             iso1A3: "ALA",
23205             iso1N3: "248",
23206             wikidata: "Q5689",
23207             nameEn: "\xC5land Islands",
23208             country: "FI",
23209             groups: ["EU", "154", "150", "UN"],
23210             callingCodes: ["358 18", "358 457"]
23211           },
23212           geometry: {
23213             type: "MultiPolygon",
23214             coordinates: [[[[19.08191, 60.19152], [20.5104, 59.15546], [21.35468, 59.67511], [21.02509, 60.12142], [21.08159, 60.20167], [21.15143, 60.54555], [20.96741, 60.71528], [19.23413, 60.61414], [19.08191, 60.19152]]]]
23215           }
23216         }, {
23217           type: "Feature",
23218           properties: {
23219             iso1A2: "AZ",
23220             iso1A3: "AZE",
23221             iso1N3: "031",
23222             wikidata: "Q227",
23223             nameEn: "Azerbaijan",
23224             groups: ["145", "142", "UN"],
23225             callingCodes: ["994"]
23226           },
23227           geometry: {
23228             type: "MultiPolygon",
23229             coordinates: [[[[46.42738, 41.91323], [46.3984, 41.84399], [46.30863, 41.79133], [46.23962, 41.75811], [46.20538, 41.77205], [46.17891, 41.72094], [46.19759, 41.62327], [46.24429, 41.59883], [46.26531, 41.63339], [46.28182, 41.60089], [46.3253, 41.60912], [46.34039, 41.5947], [46.34126, 41.57454], [46.29794, 41.5724], [46.33925, 41.4963], [46.40307, 41.48464], [46.4669, 41.43331], [46.63658, 41.37727], [46.72375, 41.28609], [46.66148, 41.20533], [46.63969, 41.09515], [46.55096, 41.1104], [46.48558, 41.0576], [46.456, 41.09984], [46.37661, 41.10805], [46.27698, 41.19011], [46.13221, 41.19479], [45.95786, 41.17956], [45.80842, 41.2229], [45.69946, 41.29545], [45.75705, 41.35157], [45.71035, 41.36208], [45.68389, 41.3539], [45.45973, 41.45898], [45.4006, 41.42402], [45.31352, 41.47168], [45.26285, 41.46433], [45.1797, 41.42231], [45.09867, 41.34065], [45.0133, 41.29747], [45.05497, 41.2464], [45.02932, 41.2101], [45.05201, 41.19211], [45.11811, 41.19967], [45.1969, 41.168], [45.19942, 41.13299], [45.08028, 41.10917], [45.06784, 41.05379], [45.12923, 41.06059], [45.1313, 41.09369], [45.1634, 41.08082], [45.16493, 41.05068], [45.1994, 41.04518], [45.25897, 41.0027], [45.26162, 41.0228], [45.28859, 41.03757], [45.35677, 40.99784], [45.39725, 41.02603], [45.44083, 41.01663], [45.40814, 40.97904], [45.60584, 40.87436], [45.55914, 40.78366], [45.4206, 40.7424], [45.35366, 40.65979], [45.45484, 40.57707], [45.42994, 40.53804], [45.65098, 40.37696], [45.95609, 40.27846], [45.97944, 40.181], [45.83779, 39.98925], [45.78642, 40.03218], [45.59806, 40.0131], [45.60895, 39.97733], [45.7833, 39.9475], [45.82533, 39.82925], [45.96543, 39.78859], [46.18493, 39.60533], [46.40286, 39.63651], [46.42465, 39.57534], [46.52117, 39.58734], [46.57098, 39.56694], [46.57721, 39.54414], [46.51027, 39.52373], [46.53051, 39.47809], [46.4013, 39.45405], [46.37795, 39.42039], [46.43244, 39.35181], [46.50093, 39.33736], [46.56476, 39.24942], [46.63481, 39.23013], [46.58032, 39.21204], [46.54141, 39.15895], [46.52584, 39.18912], [46.44022, 39.19636], [46.54296, 39.07078], [46.51805, 38.94982], [46.53497, 38.86548], [46.75752, 39.03231], [46.83822, 39.13143], [46.92539, 39.16644], [46.95341, 39.13505], [47.05771, 39.20143], [47.05927, 39.24846], [47.31301, 39.37492], [47.38978, 39.45999], [47.50099, 39.49615], [47.84774, 39.66285], [47.98977, 39.70999], [48.34264, 39.42935], [48.37385, 39.37584], [48.15984, 39.30028], [48.12404, 39.25208], [48.15361, 39.19419], [48.31239, 39.09278], [48.33884, 39.03022], [48.28437, 38.97186], [48.08627, 38.94434], [48.07734, 38.91616], [48.01409, 38.90333], [48.02581, 38.82705], [48.24773, 38.71883], [48.3146, 38.59958], [48.45084, 38.61013], [48.58793, 38.45076], [48.62217, 38.40198], [48.70001, 38.40564], [48.78979, 38.45026], [48.81072, 38.44853], [48.84969, 38.45015], [48.88288, 38.43975], [52.39847, 39.43556], [48.80971, 41.95365], [48.5867, 41.84306], [48.55078, 41.77917], [48.42301, 41.65444], [48.40277, 41.60441], [48.2878, 41.56221], [48.22064, 41.51472], [48.07587, 41.49957], [47.87973, 41.21798], [47.75831, 41.19455], [47.62288, 41.22969], [47.54504, 41.20275], [47.49004, 41.26366], [47.34579, 41.27884], [47.10762, 41.59044], [47.03757, 41.55434], [46.99554, 41.59743], [47.00955, 41.63583], [46.8134, 41.76252], [46.75269, 41.8623], [46.58924, 41.80547], [46.5332, 41.87389], [46.42738, 41.91323]], [[45.50279, 40.58424], [45.47927, 40.65023], [45.51825, 40.67382], [45.56071, 40.64765], [45.50279, 40.58424]]], [[[45.00864, 41.03411], [45.03792, 41.03938], [45.04517, 41.06653], [45.03406, 41.07931], [45.00864, 41.09407], [44.97169, 41.09176], [44.95383, 41.07553], [44.96031, 41.06345], [44.9903, 41.05657], [45.00864, 41.03411]]], [[[45.21324, 40.9817], [45.23095, 40.97828], [45.23487, 41.00226], [45.20625, 41.01484], [45.18382, 41.0066], [45.19312, 40.98998], [45.20518, 40.99348], [45.21219, 40.99001], [45.21324, 40.9817]]], [[[45.46992, 39.49888], [45.29606, 39.57654], [45.30385, 39.61373], [45.23535, 39.61373], [45.21784, 39.58074], [45.17464, 39.58614], [45.18554, 39.67846], [45.06604, 39.79277], [44.92869, 39.72157], [44.88354, 39.74432], [44.75779, 39.7148], [44.80977, 39.65768], [44.81043, 39.62677], [44.88916, 39.59653], [44.96746, 39.42998], [45.05932, 39.36435], [45.08751, 39.35052], [45.16168, 39.21952], [45.30489, 39.18333], [45.40148, 39.09007], [45.40452, 39.07224], [45.44811, 39.04927], [45.44966, 38.99243], [45.6131, 38.964], [45.6155, 38.94304], [45.65172, 38.95199], [45.83883, 38.90768], [45.90266, 38.87739], [45.94624, 38.89072], [46.00228, 38.87376], [46.06766, 38.87861], [46.14785, 38.84206], [46.06973, 39.0744], [46.02303, 39.09978], [45.99774, 39.28931], [45.79225, 39.3695], [45.83, 39.46487], [45.80804, 39.56716], [45.70547, 39.60174], [45.46992, 39.49888]]]]
23230           }
23231         }, {
23232           type: "Feature",
23233           properties: {
23234             iso1A2: "BA",
23235             iso1A3: "BIH",
23236             iso1N3: "070",
23237             wikidata: "Q225",
23238             nameEn: "Bosnia and Herzegovina",
23239             groups: ["039", "150", "UN"],
23240             callingCodes: ["387"]
23241           },
23242           geometry: {
23243             type: "MultiPolygon",
23244             coordinates: [[[[17.84826, 45.04489], [17.66571, 45.13408], [17.59104, 45.10816], [17.51469, 45.10791], [17.47589, 45.12656], [17.45615, 45.12523], [17.4498, 45.16119], [17.41229, 45.13335], [17.33573, 45.14521], [17.32092, 45.16246], [17.26815, 45.18444], [17.25131, 45.14957], [17.24325, 45.146], [17.18438, 45.14764], [17.0415, 45.20759], [16.9385, 45.22742], [16.92405, 45.27607], [16.83804, 45.18951], [16.81137, 45.18434], [16.78219, 45.19002], [16.74845, 45.20393], [16.64962, 45.20714], [16.60194, 45.23042], [16.56559, 45.22307], [16.5501, 45.2212], [16.52982, 45.22713], [16.49155, 45.21153], [16.4634, 45.14522], [16.40023, 45.1147], [16.38309, 45.05955], [16.38219, 45.05139], [16.3749, 45.05206], [16.35863, 45.03529], [16.35404, 45.00241], [16.29036, 44.99732], [16.12153, 45.09616], [15.98412, 45.23088], [15.83512, 45.22459], [15.76371, 45.16508], [15.78842, 45.11519], [15.74585, 45.0638], [15.78568, 44.97401], [15.74723, 44.96818], [15.76096, 44.87045], [15.79472, 44.8455], [15.72584, 44.82334], [15.8255, 44.71501], [15.89348, 44.74964], [16.05828, 44.61538], [16.00884, 44.58605], [16.03012, 44.55572], [16.10566, 44.52586], [16.16814, 44.40679], [16.12969, 44.38275], [16.21346, 44.35231], [16.18688, 44.27012], [16.36864, 44.08263], [16.43662, 44.07523], [16.43629, 44.02826], [16.50528, 44.0244], [16.55472, 43.95326], [16.70922, 43.84887], [16.75316, 43.77157], [16.80736, 43.76011], [17.00585, 43.58037], [17.15828, 43.49376], [17.24411, 43.49376], [17.29699, 43.44542], [17.25579, 43.40353], [17.286, 43.33065], [17.46986, 43.16559], [17.64268, 43.08595], [17.70879, 42.97223], [17.5392, 42.92787], [17.6444, 42.88641], [17.68151, 42.92725], [17.7948, 42.89556], [17.80854, 42.9182], [17.88201, 42.83668], [18.24318, 42.6112], [18.36197, 42.61423], [18.43735, 42.55921], [18.49778, 42.58409], [18.53751, 42.57376], [18.55504, 42.58409], [18.52232, 42.62279], [18.57373, 42.64429], [18.54841, 42.68328], [18.54603, 42.69171], [18.55221, 42.69045], [18.56789, 42.72074], [18.47324, 42.74992], [18.45921, 42.81682], [18.47633, 42.85829], [18.4935, 42.86433], [18.49661, 42.89306], [18.49076, 42.95553], [18.52232, 43.01451], [18.66254, 43.03928], [18.64735, 43.14766], [18.66605, 43.2056], [18.71747, 43.2286], [18.6976, 43.25243], [18.76538, 43.29838], [18.85342, 43.32426], [18.84794, 43.33735], [18.83912, 43.34795], [18.90911, 43.36383], [18.95819, 43.32899], [18.95001, 43.29327], [19.00844, 43.24988], [19.04233, 43.30008], [19.08206, 43.29668], [19.08673, 43.31453], [19.04071, 43.397], [19.01078, 43.43854], [18.96053, 43.45042], [18.95469, 43.49367], [18.91379, 43.50299], [19.01078, 43.55806], [19.04934, 43.50384], [19.13933, 43.5282], [19.15685, 43.53943], [19.22807, 43.5264], [19.24774, 43.53061], [19.2553, 43.5938], [19.33426, 43.58833], [19.36653, 43.60921], [19.41941, 43.54056], [19.42696, 43.57987], [19.50455, 43.58385], [19.5176, 43.71403], [19.3986, 43.79668], [19.23465, 43.98764], [19.24363, 44.01502], [19.38439, 43.96611], [19.52515, 43.95573], [19.56498, 43.99922], [19.61836, 44.01464], [19.61991, 44.05254], [19.57467, 44.04716], [19.55999, 44.06894], [19.51167, 44.08158], [19.47321, 44.1193], [19.48386, 44.14332], [19.47338, 44.15034], [19.43905, 44.13088], [19.40927, 44.16722], [19.3588, 44.18353], [19.34773, 44.23244], [19.32464, 44.27185], [19.26945, 44.26957], [19.23306, 44.26097], [19.20508, 44.2917], [19.18328, 44.28383], [19.16741, 44.28648], [19.13332, 44.31492], [19.13556, 44.338], [19.11547, 44.34218], [19.1083, 44.3558], [19.11865, 44.36712], [19.10298, 44.36924], [19.10365, 44.37795], [19.10704, 44.38249], [19.10749, 44.39421], [19.11785, 44.40313], [19.14681, 44.41463], [19.14837, 44.45253], [19.12278, 44.50132], [19.13369, 44.52521], [19.16699, 44.52197], [19.26388, 44.65412], [19.32543, 44.74058], [19.36722, 44.88164], [19.18183, 44.92055], [19.01994, 44.85493], [18.8704, 44.85097], [18.76347, 44.90669], [18.76369, 44.93707], [18.80661, 44.93561], [18.78357, 44.97741], [18.65723, 45.07544], [18.47939, 45.05871], [18.41896, 45.11083], [18.32077, 45.1021], [18.24387, 45.13699], [18.1624, 45.07654], [18.03121, 45.12632], [18.01594, 45.15163], [17.99479, 45.14958], [17.97834, 45.13831], [17.97336, 45.12245], [17.93706, 45.08016], [17.87148, 45.04645], [17.84826, 45.04489]]]]
23245           }
23246         }, {
23247           type: "Feature",
23248           properties: {
23249             iso1A2: "BB",
23250             iso1A3: "BRB",
23251             iso1N3: "052",
23252             wikidata: "Q244",
23253             nameEn: "Barbados",
23254             groups: ["029", "003", "419", "019", "UN"],
23255             driveSide: "left",
23256             callingCodes: ["1 246"]
23257           },
23258           geometry: {
23259             type: "MultiPolygon",
23260             coordinates: [[[[-58.56442, 13.24471], [-59.80731, 13.87556], [-59.82929, 12.70644], [-58.56442, 13.24471]]]]
23261           }
23262         }, {
23263           type: "Feature",
23264           properties: {
23265             iso1A2: "BD",
23266             iso1A3: "BGD",
23267             iso1N3: "050",
23268             wikidata: "Q902",
23269             nameEn: "Bangladesh",
23270             groups: ["034", "142", "UN"],
23271             driveSide: "left",
23272             callingCodes: ["880"]
23273           },
23274           geometry: {
23275             type: "MultiPolygon",
23276             coordinates: [[[[89.15869, 26.13708], [89.08899, 26.38845], [88.95612, 26.4564], [88.92357, 26.40711], [88.91321, 26.37984], [89.05328, 26.2469], [88.85004, 26.23211], [88.78961, 26.31093], [88.67837, 26.26291], [88.69485, 26.38353], [88.62144, 26.46783], [88.4298, 26.54489], [88.41196, 26.63837], [88.33093, 26.48929], [88.35153, 26.45241], [88.36938, 26.48683], [88.48749, 26.45855], [88.51649, 26.35923], [88.35153, 26.29123], [88.34757, 26.22216], [88.1844, 26.14417], [88.16581, 26.0238], [88.08804, 25.91334], [88.13138, 25.78773], [88.242, 25.80811], [88.45103, 25.66245], [88.4559, 25.59227], [88.677, 25.46959], [88.81296, 25.51546], [88.85278, 25.34679], [89.01105, 25.30303], [89.00463, 25.26583], [88.94067, 25.18534], [88.44766, 25.20149], [88.46277, 25.07468], [88.33917, 24.86803], [88.27325, 24.88796], [88.21832, 24.96642], [88.14004, 24.93529], [88.15515, 24.85806], [88.00683, 24.66477], [88.08786, 24.63232], [88.12296, 24.51301], [88.50934, 24.32474], [88.68801, 24.31464], [88.74841, 24.1959], [88.6976, 24.14703], [88.73743, 23.91751], [88.66189, 23.87607], [88.58087, 23.87105], [88.56507, 23.64044], [88.74841, 23.47361], [88.79351, 23.50535], [88.79254, 23.46028], [88.71133, 23.2492], [88.99148, 23.21134], [88.86377, 23.08759], [88.88327, 23.03885], [88.87063, 22.95235], [88.96713, 22.83346], [88.9151, 22.75228], [88.94614, 22.66941], [88.9367, 22.58527], [89.07114, 22.15335], [89.08044, 21.41871], [92.47409, 20.38654], [92.26071, 21.05697], [92.17752, 21.17445], [92.20087, 21.337], [92.37939, 21.47764], [92.43158, 21.37025], [92.55105, 21.3856], [92.60187, 21.24615], [92.68152, 21.28454], [92.59775, 21.6092], [92.62187, 21.87037], [92.60949, 21.97638], [92.56616, 22.13554], [92.60029, 22.1522], [92.5181, 22.71441], [92.37665, 22.9435], [92.38214, 23.28705], [92.26541, 23.70392], [92.15417, 23.73409], [92.04706, 23.64229], [91.95093, 23.73284], [91.95642, 23.47361], [91.84789, 23.42235], [91.76417, 23.26619], [91.81634, 23.08001], [91.7324, 23.00043], [91.61571, 22.93929], [91.54993, 23.01051], [91.46615, 23.2328], [91.4035, 23.27522], [91.40848, 23.07117], [91.36453, 23.06612], [91.28293, 23.37538], [91.15579, 23.6599], [91.25192, 23.83463], [91.22308, 23.89616], [91.29587, 24.0041], [91.35741, 23.99072], [91.37414, 24.10693], [91.55542, 24.08687], [91.63782, 24.1132], [91.65292, 24.22095], [91.73257, 24.14703], [91.76004, 24.23848], [91.82596, 24.22345], [91.89258, 24.14674], [91.96603, 24.3799], [92.11662, 24.38997], [92.15796, 24.54435], [92.25854, 24.9191], [92.38626, 24.86055], [92.49887, 24.88796], [92.39147, 25.01471], [92.33957, 25.07593], [92.0316, 25.1834], [91.63648, 25.12846], [91.25517, 25.20677], [90.87427, 25.15799], [90.65042, 25.17788], [90.40034, 25.1534], [90.1155, 25.22686], [89.90478, 25.31038], [89.87629, 25.28337], [89.83371, 25.29548], [89.84086, 25.31854], [89.81208, 25.37244], [89.86129, 25.61714], [89.84388, 25.70042], [89.80585, 25.82489], [89.86592, 25.93115], [89.77728, 26.04254], [89.77865, 26.08387], [89.73581, 26.15818], [89.70201, 26.15138], [89.63968, 26.22595], [89.57101, 25.9682], [89.53515, 26.00382], [89.35953, 26.0077], [89.15869, 26.13708]]]]
23277           }
23278         }, {
23279           type: "Feature",
23280           properties: {
23281             iso1A2: "BE",
23282             iso1A3: "BEL",
23283             iso1N3: "056",
23284             wikidata: "Q31",
23285             nameEn: "Belgium",
23286             groups: ["EU", "155", "150", "UN"],
23287             callingCodes: ["32"]
23288           },
23289           geometry: {
23290             type: "MultiPolygon",
23291             coordinates: [[[[4.93295, 51.44945], [4.93909, 51.44632], [4.9524, 51.45014], [4.95244, 51.45207], [4.93295, 51.44945]]], [[[4.91493, 51.4353], [4.92652, 51.43329], [4.92952, 51.42984], [4.93986, 51.43064], [4.94265, 51.44003], [4.93471, 51.43861], [4.93416, 51.44185], [4.94025, 51.44193], [4.93544, 51.44634], [4.92879, 51.44161], [4.92815, 51.43856], [4.92566, 51.44273], [4.92811, 51.4437], [4.92287, 51.44741], [4.91811, 51.44621], [4.92227, 51.44252], [4.91935, 51.43634], [4.91493, 51.4353]]], [[[4.82946, 51.4213], [4.82409, 51.44736], [4.84139, 51.4799], [4.78803, 51.50284], [4.77321, 51.50529], [4.74578, 51.48937], [4.72935, 51.48424], [4.65442, 51.42352], [4.57489, 51.4324], [4.53521, 51.4243], [4.52846, 51.45002], [4.54675, 51.47265], [4.5388, 51.48184], [4.47736, 51.4778], [4.38122, 51.44905], [4.39747, 51.43316], [4.38064, 51.41965], [4.43777, 51.36989], [4.39292, 51.35547], [4.34086, 51.35738], [4.33265, 51.37687], [4.21923, 51.37443], [4.24024, 51.35371], [4.16721, 51.29348], [4.05165, 51.24171], [4.01957, 51.24504], [3.97889, 51.22537], [3.90125, 51.20371], [3.78783, 51.2151], [3.78999, 51.25766], [3.58939, 51.30064], [3.51502, 51.28697], [3.52698, 51.2458], [3.43488, 51.24135], [3.41704, 51.25933], [3.38289, 51.27331], [3.35847, 51.31572], [3.38696, 51.33436], [3.36263, 51.37112], [2.56575, 51.85301], [2.18458, 51.52087], [2.55904, 51.07014], [2.57551, 51.00326], [2.63074, 50.94746], [2.59093, 50.91751], [2.63331, 50.81457], [2.71165, 50.81295], [2.81056, 50.71773], [2.8483, 50.72276], [2.86985, 50.7033], [2.87937, 50.70298], [2.88504, 50.70656], [2.90069, 50.69263], [2.91036, 50.6939], [2.90873, 50.702], [2.95019, 50.75138], [2.96778, 50.75242], [3.00537, 50.76588], [3.04314, 50.77674], [3.09163, 50.77717], [3.10614, 50.78303], [3.11206, 50.79416], [3.11987, 50.79188], [3.1257, 50.78603], [3.15017, 50.79031], [3.16476, 50.76843], [3.18339, 50.74981], [3.18811, 50.74025], [3.20064, 50.73547], [3.19017, 50.72569], [3.20845, 50.71662], [3.22042, 50.71019], [3.24593, 50.71389], [3.26063, 50.70086], [3.26141, 50.69151], [3.2536, 50.68977], [3.264, 50.67668], [3.23951, 50.6585], [3.2729, 50.60718], [3.28575, 50.52724], [3.37693, 50.49538], [3.44629, 50.51009], [3.47385, 50.53397], [3.51564, 50.5256], [3.49509, 50.48885], [3.5683, 50.50192], [3.58361, 50.49049], [3.61014, 50.49568], [3.64426, 50.46275], [3.66153, 50.45165], [3.67494, 50.40239], [3.67262, 50.38663], [3.65709, 50.36873], [3.66976, 50.34563], [3.71009, 50.30305], [3.70987, 50.3191], [3.73911, 50.34809], [3.84314, 50.35219], [3.90781, 50.32814], [3.96771, 50.34989], [4.0268, 50.35793], [4.0689, 50.3254], [4.10237, 50.31247], [4.10957, 50.30234], [4.11954, 50.30425], [4.13665, 50.25609], [4.16808, 50.25786], [4.15524, 50.2833], [4.17347, 50.28838], [4.17861, 50.27443], [4.20651, 50.27333], [4.21945, 50.25539], [4.15524, 50.21103], [4.16014, 50.19239], [4.13561, 50.13078], [4.20147, 50.13535], [4.23101, 50.06945], [4.16294, 50.04719], [4.13508, 50.01976], [4.14239, 49.98034], [4.20532, 49.95803], [4.31963, 49.97043], [4.35051, 49.95315], [4.43488, 49.94122], [4.51098, 49.94659], [4.5414, 49.96911], [4.68695, 49.99685], [4.70064, 50.09384], [4.75237, 50.11314], [4.82438, 50.16878], [4.83279, 50.15331], [4.88602, 50.15182], [4.8382, 50.06738], [4.78827, 49.95609], [4.88529, 49.9236], [4.85134, 49.86457], [4.86965, 49.82271], [4.85464, 49.78995], [4.96714, 49.79872], [5.09249, 49.76193], [5.14545, 49.70287], [5.26232, 49.69456], [5.31465, 49.66846], [5.33039, 49.6555], [5.30214, 49.63055], [5.3137, 49.61225], [5.33851, 49.61599], [5.34837, 49.62889], [5.3974, 49.61596], [5.43713, 49.5707], [5.46734, 49.52648], [5.46541, 49.49825], [5.55001, 49.52729], [5.60909, 49.51228], [5.64505, 49.55146], [5.75649, 49.54321], [5.7577, 49.55915], [5.77435, 49.56298], [5.79195, 49.55228], [5.81838, 49.54777], [5.84143, 49.5533], [5.84692, 49.55663], [5.8424, 49.56082], [5.87256, 49.57539], [5.86986, 49.58756], [5.84971, 49.58674], [5.84826, 49.5969], [5.8762, 49.60898], [5.87609, 49.62047], [5.88393, 49.62802], [5.88552, 49.63507], [5.90599, 49.63853], [5.90164, 49.6511], [5.9069, 49.66377], [5.86175, 49.67862], [5.86527, 49.69291], [5.88677, 49.70951], [5.86503, 49.72739], [5.84193, 49.72161], [5.82562, 49.72395], [5.83149, 49.74729], [5.82245, 49.75048], [5.78871, 49.7962], [5.75409, 49.79239], [5.74953, 49.81428], [5.74364, 49.82058], [5.74844, 49.82435], [5.7404, 49.83452], [5.74076, 49.83823], [5.74975, 49.83933], [5.74953, 49.84709], [5.75884, 49.84811], [5.74567, 49.85368], [5.75861, 49.85631], [5.75269, 49.8711], [5.78415, 49.87922], [5.73621, 49.89796], [5.77314, 49.93646], [5.77291, 49.96056], [5.80833, 49.96451], [5.81163, 49.97142], [5.83467, 49.97823], [5.83968, 49.9892], [5.82331, 49.99662], [5.81866, 50.01286], [5.8551, 50.02683], [5.86904, 50.04614], [5.85474, 50.06342], [5.8857, 50.07824], [5.89488, 50.11476], [5.95929, 50.13295], [5.96453, 50.17259], [6.02488, 50.18283], [6.03093, 50.16362], [6.06406, 50.15344], [6.08577, 50.17246], [6.12028, 50.16374], [6.1137, 50.13668], [6.1379, 50.12964], [6.15298, 50.14126], [6.14132, 50.14971], [6.14588, 50.17106], [6.18739, 50.1822], [6.18364, 50.20815], [6.16853, 50.2234], [6.208, 50.25179], [6.28797, 50.27458], [6.29949, 50.30887], [6.32488, 50.32333], [6.35701, 50.31139], [6.40641, 50.32425], [6.40785, 50.33557], [6.3688, 50.35898], [6.34406, 50.37994], [6.36852, 50.40776], [6.37219, 50.45397], [6.34005, 50.46083], [6.3465, 50.48833], [6.30809, 50.50058], [6.26637, 50.50272], [6.22335, 50.49578], [6.20599, 50.52089], [6.19193, 50.5212], [6.18716, 50.52653], [6.19579, 50.5313], [6.19735, 50.53576], [6.17802, 50.54179], [6.17739, 50.55875], [6.20281, 50.56952], [6.22581, 50.5907], [6.24005, 50.58732], [6.24888, 50.59869], [6.2476, 50.60392], [6.26957, 50.62444], [6.17852, 50.6245], [6.11707, 50.72231], [6.04428, 50.72861], [6.0406, 50.71848], [6.0326, 50.72647], [6.03889, 50.74618], [6.01976, 50.75398], [5.97545, 50.75441], [5.95942, 50.7622], [5.89132, 50.75124], [5.89129, 50.75125], [5.88734, 50.77092], [5.84888, 50.75448], [5.84548, 50.76542], [5.80673, 50.7558], [5.77513, 50.78308], [5.76533, 50.78159], [5.74356, 50.7691], [5.73904, 50.75674], [5.72216, 50.76398], [5.69469, 50.75529], [5.68091, 50.75804], [5.70107, 50.7827], [5.68995, 50.79641], [5.70118, 50.80764], [5.65259, 50.82309], [5.64009, 50.84742], [5.64504, 50.87107], [5.67886, 50.88142], [5.69858, 50.91046], [5.71626, 50.90796], [5.72644, 50.91167], [5.72545, 50.92312], [5.74644, 50.94723], [5.75927, 50.95601], [5.74752, 50.96202], [5.72875, 50.95428], [5.71864, 50.96092], [5.76242, 50.99703], [5.77688, 51.02483], [5.75961, 51.03113], [5.77258, 51.06196], [5.79835, 51.05834], [5.79903, 51.09371], [5.82921, 51.09328], [5.83226, 51.10585], [5.8109, 51.10861], [5.80798, 51.11661], [5.85508, 51.14445], [5.82564, 51.16753], [5.77697, 51.1522], [5.77735, 51.17845], [5.74617, 51.18928], [5.70344, 51.1829], [5.65528, 51.18736], [5.65145, 51.19788], [5.5603, 51.22249], [5.5569, 51.26544], [5.515, 51.29462], [5.48476, 51.30053], [5.46519, 51.2849], [5.4407, 51.28169], [5.41672, 51.26248], [5.347, 51.27502], [5.33886, 51.26314], [5.29716, 51.26104], [5.26461, 51.26693], [5.23814, 51.26064], [5.22542, 51.26888], [5.24244, 51.30495], [5.2002, 51.32243], [5.16222, 51.31035], [5.13377, 51.31592], [5.13105, 51.34791], [5.07102, 51.39469], [5.10456, 51.43163], [5.07891, 51.4715], [5.04774, 51.47022], [5.03281, 51.48679], [5.0106, 51.47167], [5.00393, 51.44406], [4.92152, 51.39487], [4.90016, 51.41404], [4.84988, 51.41502], [4.78941, 51.41102], [4.77229, 51.41337], [4.76577, 51.43046], [4.78314, 51.43319], [4.82946, 51.4213]]]]
23292           }
23293         }, {
23294           type: "Feature",
23295           properties: {
23296             iso1A2: "BF",
23297             iso1A3: "BFA",
23298             iso1N3: "854",
23299             wikidata: "Q965",
23300             nameEn: "Burkina Faso",
23301             groups: ["011", "202", "002", "UN"],
23302             callingCodes: ["226"]
23303           },
23304           geometry: {
23305             type: "MultiPolygon",
23306             coordinates: [[[[0.23859, 15.00135], [0.06588, 14.96961], [-0.24673, 15.07805], [-0.72004, 15.08655], [-1.05875, 14.7921], [-1.32166, 14.72774], [-1.68083, 14.50023], [-1.97945, 14.47709], [-1.9992, 14.19011], [-2.10223, 14.14878], [-2.47587, 14.29671], [-2.66175, 14.14713], [-2.84667, 14.05532], [-2.90831, 13.81174], [-2.88189, 13.64921], [-3.26407, 13.70699], [-3.28396, 13.5422], [-3.23599, 13.29035], [-3.43507, 13.27272], [-3.4313, 13.1588], [-3.54454, 13.1781], [-3.7911, 13.36665], [-3.96282, 13.38164], [-3.90558, 13.44375], [-3.96501, 13.49778], [-4.34477, 13.12927], [-4.21819, 12.95722], [-4.238, 12.71467], [-4.47356, 12.71252], [-4.41412, 12.31922], [-4.57703, 12.19875], [-4.54841, 12.1385], [-4.62546, 12.13204], [-4.62987, 12.06531], [-4.70692, 12.06746], [-4.72893, 12.01579], [-5.07897, 11.97918], [-5.26389, 11.84778], [-5.40258, 11.8327], [-5.26389, 11.75728], [-5.29251, 11.61715], [-5.22867, 11.60421], [-5.20665, 11.43811], [-5.25509, 11.36905], [-5.25949, 11.24816], [-5.32553, 11.21578], [-5.32994, 11.13371], [-5.49284, 11.07538], [-5.41579, 10.84628], [-5.47083, 10.75329], [-5.46643, 10.56074], [-5.51058, 10.43177], [-5.39602, 10.2929], [-5.12465, 10.29788], [-4.96453, 9.99923], [-4.96621, 9.89132], [-4.6426, 9.70696], [-4.31392, 9.60062], [-4.25999, 9.76012], [-3.69703, 9.94279], [-3.31779, 9.91125], [-3.27228, 9.84981], [-3.19306, 9.93781], [-3.16609, 9.85147], [-3.00765, 9.74019], [-2.93012, 9.57403], [-2.76494, 9.40778], [-2.68802, 9.49343], [-2.76534, 9.56589], [-2.74174, 9.83172], [-2.83108, 10.40252], [-2.94232, 10.64281], [-2.83373, 11.0067], [-0.67143, 10.99811], [-0.61937, 10.91305], [-0.44298, 11.04292], [-0.42391, 11.11661], [-0.38219, 11.12596], [-0.35955, 11.07801], [-0.28566, 11.12713], [-0.27374, 11.17157], [-0.13493, 11.14075], [0.50388, 11.01011], [0.48852, 10.98561], [0.50521, 10.98035], [0.4958, 10.93269], [0.66104, 10.99964], [0.91245, 10.99597], [0.9813, 11.08876], [1.03409, 11.04719], [1.42823, 11.46822], [2.00988, 11.42227], [2.29983, 11.68254], [2.39723, 11.89473], [2.05785, 12.35539], [2.26349, 12.41915], [0.99167, 13.10727], [0.99253, 13.37515], [1.18873, 13.31771], [1.21217, 13.37853], [1.24516, 13.33968], [1.28509, 13.35488], [1.24429, 13.39373], [1.20088, 13.38951], [1.02813, 13.46635], [0.99514, 13.5668], [0.77637, 13.64442], [0.77377, 13.6866], [0.61924, 13.68491], [0.38051, 14.05575], [0.16936, 14.51654], [0.23859, 15.00135]]]]
23307           }
23308         }, {
23309           type: "Feature",
23310           properties: {
23311             iso1A2: "BG",
23312             iso1A3: "BGR",
23313             iso1N3: "100",
23314             wikidata: "Q219",
23315             nameEn: "Bulgaria",
23316             groups: ["EU", "151", "150", "UN"],
23317             callingCodes: ["359"]
23318           },
23319           geometry: {
23320             type: "MultiPolygon",
23321             coordinates: [[[[23.05288, 43.79494], [22.85314, 43.84452], [22.83753, 43.88055], [22.87873, 43.9844], [23.01674, 44.01946], [23.04988, 44.07694], [22.67173, 44.21564], [22.61711, 44.16938], [22.61688, 44.06534], [22.41449, 44.00514], [22.35558, 43.81281], [22.41043, 43.69566], [22.47582, 43.6558], [22.53397, 43.47225], [22.82036, 43.33665], [22.89727, 43.22417], [23.00806, 43.19279], [22.98104, 43.11199], [22.89521, 43.03625], [22.78397, 42.98253], [22.74826, 42.88701], [22.54302, 42.87774], [22.43309, 42.82057], [22.4997, 42.74144], [22.43983, 42.56851], [22.55669, 42.50144], [22.51961, 42.3991], [22.47498, 42.3915], [22.45919, 42.33822], [22.34773, 42.31725], [22.38136, 42.30339], [22.47251, 42.20393], [22.50289, 42.19527], [22.51224, 42.15457], [22.67701, 42.06614], [22.86749, 42.02275], [22.90254, 41.87587], [22.96682, 41.77137], [23.01239, 41.76527], [23.03342, 41.71034], [22.95513, 41.63265], [22.96331, 41.35782], [22.93334, 41.34104], [23.1833, 41.31755], [23.21953, 41.33773], [23.22771, 41.37106], [23.31301, 41.40525], [23.33639, 41.36317], [23.40416, 41.39999], [23.52453, 41.40262], [23.63203, 41.37632], [23.67644, 41.41139], [23.76525, 41.40175], [23.80148, 41.43943], [23.89613, 41.45257], [23.91483, 41.47971], [23.96975, 41.44118], [24.06908, 41.46132], [24.06323, 41.53222], [24.10063, 41.54796], [24.18126, 41.51735], [24.27124, 41.57682], [24.30513, 41.51297], [24.52599, 41.56808], [24.61129, 41.42278], [24.71529, 41.41928], [24.8041, 41.34913], [24.82514, 41.4035], [24.86136, 41.39298], [24.90928, 41.40876], [24.942, 41.38685], [25.11611, 41.34212], [25.28322, 41.23411], [25.48187, 41.28506], [25.52394, 41.2798], [25.55082, 41.31667], [25.61042, 41.30614], [25.66183, 41.31316], [25.70507, 41.29209], [25.8266, 41.34563], [25.87919, 41.30526], [26.12926, 41.35878], [26.16548, 41.42278], [26.20288, 41.43943], [26.14796, 41.47533], [26.176, 41.50072], [26.17951, 41.55409], [26.14328, 41.55496], [26.15146, 41.60828], [26.07083, 41.64584], [26.06148, 41.70345], [26.16841, 41.74858], [26.21325, 41.73223], [26.22888, 41.74139], [26.2654, 41.71544], [26.30255, 41.70925], [26.35957, 41.71149], [26.32952, 41.73637], [26.33589, 41.76802], [26.36952, 41.82265], [26.53968, 41.82653], [26.57961, 41.90024], [26.56051, 41.92995], [26.62996, 41.97644], [26.79143, 41.97386], [26.95638, 42.00741], [27.03277, 42.0809], [27.08486, 42.08735], [27.19251, 42.06028], [27.22376, 42.10152], [27.27411, 42.10409], [27.45478, 41.96591], [27.52379, 41.93756], [27.55191, 41.90928], [27.69949, 41.97515], [27.81235, 41.94803], [27.83492, 41.99709], [27.91479, 41.97902], [28.02971, 41.98066], [28.32297, 41.98371], [29.24336, 43.70874], [28.23293, 43.76], [27.99558, 43.84193], [27.92008, 44.00761], [27.73468, 43.95326], [27.64542, 44.04958], [27.60834, 44.01206], [27.39757, 44.0141], [27.26845, 44.12602], [26.95141, 44.13555], [26.62712, 44.05698], [26.38764, 44.04356], [26.10115, 43.96908], [26.05584, 43.90925], [25.94911, 43.85745], [25.72792, 43.69263], [25.39528, 43.61866], [25.17144, 43.70261], [25.10718, 43.6831], [24.96682, 43.72693], [24.73542, 43.68523], [24.62281, 43.74082], [24.50264, 43.76314], [24.35364, 43.70211], [24.18149, 43.68218], [23.73978, 43.80627], [23.61687, 43.79289], [23.4507, 43.84936], [23.26772, 43.84843], [23.05288, 43.79494]]]]
23322           }
23323         }, {
23324           type: "Feature",
23325           properties: {
23326             iso1A2: "BH",
23327             iso1A3: "BHR",
23328             iso1N3: "048",
23329             wikidata: "Q398",
23330             nameEn: "Bahrain",
23331             groups: ["145", "142", "UN"],
23332             callingCodes: ["973"]
23333           },
23334           geometry: {
23335             type: "MultiPolygon",
23336             coordinates: [[[[50.93865, 26.30758], [50.71771, 26.73086], [50.38162, 26.53976], [50.26923, 26.08243], [50.302, 25.87592], [50.57069, 25.57887], [50.80824, 25.54641], [50.7801, 25.595], [50.86149, 25.6965], [50.81266, 25.88946], [50.93865, 26.30758]]]]
23337           }
23338         }, {
23339           type: "Feature",
23340           properties: {
23341             iso1A2: "BI",
23342             iso1A3: "BDI",
23343             iso1N3: "108",
23344             wikidata: "Q967",
23345             nameEn: "Burundi",
23346             groups: ["014", "202", "002", "UN"],
23347             callingCodes: ["257"]
23348           },
23349           geometry: {
23350             type: "MultiPolygon",
23351             coordinates: [[[[30.54501, -2.41404], [30.42933, -2.31064], [30.14034, -2.43626], [29.95911, -2.33348], [29.88237, -2.75105], [29.36805, -2.82933], [29.32234, -2.6483], [29.0562, -2.58632], [29.04081, -2.7416], [29.00167, -2.78523], [29.00404, -2.81978], [29.0505, -2.81774], [29.09119, -2.87871], [29.09797, -2.91935], [29.16037, -2.95457], [29.17258, -2.99385], [29.25633, -3.05471], [29.21463, -3.3514], [29.23708, -3.75856], [29.43673, -4.44845], [29.63827, -4.44681], [29.75109, -4.45836], [29.77289, -4.41733], [29.82885, -4.36153], [29.88172, -4.35743], [30.03323, -4.26631], [30.22042, -4.01738], [30.45915, -3.56532], [30.84165, -3.25152], [30.83823, -2.97837], [30.6675, -2.98987], [30.57926, -2.89791], [30.4987, -2.9573], [30.40662, -2.86151], [30.52747, -2.65841], [30.41789, -2.66266], [30.54501, -2.41404]]]]
23352           }
23353         }, {
23354           type: "Feature",
23355           properties: {
23356             iso1A2: "BJ",
23357             iso1A3: "BEN",
23358             iso1N3: "204",
23359             wikidata: "Q962",
23360             nameEn: "Benin",
23361             aliases: ["DY"],
23362             groups: ["011", "202", "002", "UN"],
23363             callingCodes: ["229"]
23364           },
23365           geometry: {
23366             type: "MultiPolygon",
23367             coordinates: [[[[3.59375, 11.70269], [3.48187, 11.86092], [3.31613, 11.88495], [3.25352, 12.01467], [2.83978, 12.40585], [2.6593, 12.30631], [2.37783, 12.24804], [2.39657, 12.10952], [2.45824, 11.98672], [2.39723, 11.89473], [2.29983, 11.68254], [2.00988, 11.42227], [1.42823, 11.46822], [1.03409, 11.04719], [0.9813, 11.08876], [0.91245, 10.99597], [0.8804, 10.803], [0.80358, 10.71459], [0.77666, 10.37665], [1.35507, 9.99525], [1.36624, 9.5951], [1.33675, 9.54765], [1.41746, 9.3226], [1.5649, 9.16941], [1.61838, 9.0527], [1.64249, 6.99562], [1.55877, 6.99737], [1.61812, 6.74843], [1.58105, 6.68619], [1.76906, 6.43189], [1.79826, 6.28221], [1.62913, 6.24075], [1.67336, 6.02702], [2.74181, 6.13349], [2.70566, 6.38038], [2.70464, 6.50831], [2.74334, 6.57291], [2.7325, 6.64057], [2.78204, 6.70514], [2.78823, 6.76356], [2.73405, 6.78508], [2.74024, 6.92802], [2.71702, 6.95722], [2.76965, 7.13543], [2.74489, 7.42565], [2.79442, 7.43486], [2.78668, 7.5116], [2.73405, 7.5423], [2.73095, 7.7755], [2.67523, 7.87825], [2.77907, 9.06924], [3.08017, 9.10006], [3.14147, 9.28375], [3.13928, 9.47167], [3.25093, 9.61632], [3.34726, 9.70696], [3.32099, 9.78032], [3.35383, 9.83641], [3.54429, 9.87739], [3.66908, 10.18136], [3.57275, 10.27185], [3.6844, 10.46351], [3.78292, 10.40538], [3.84243, 10.59316], [3.71505, 11.13015], [3.49175, 11.29765], [3.59375, 11.70269]]]]
23368           }
23369         }, {
23370           type: "Feature",
23371           properties: {
23372             iso1A2: "BL",
23373             iso1A3: "BLM",
23374             iso1N3: "652",
23375             wikidata: "Q25362",
23376             nameEn: "Saint-Barth\xE9lemy",
23377             country: "FR",
23378             groups: ["Q1451600", "029", "003", "419", "019", "UN"],
23379             callingCodes: ["590"]
23380           },
23381           geometry: {
23382             type: "MultiPolygon",
23383             coordinates: [[[[-62.62718, 18.26185], [-63.1055, 17.86651], [-62.34423, 17.49165], [-62.62718, 18.26185]]]]
23384           }
23385         }, {
23386           type: "Feature",
23387           properties: {
23388             iso1A2: "BM",
23389             iso1A3: "BMU",
23390             iso1N3: "060",
23391             wikidata: "Q23635",
23392             nameEn: "Bermuda",
23393             country: "GB",
23394             groups: ["BOTS", "021", "003", "019", "UN"],
23395             driveSide: "left",
23396             callingCodes: ["1 441"]
23397           },
23398           geometry: {
23399             type: "MultiPolygon",
23400             coordinates: [[[[-63.20987, 32.6953], [-65.31453, 32.68437], [-65.63955, 31.43417], [-63.20987, 32.6953]]]]
23401           }
23402         }, {
23403           type: "Feature",
23404           properties: {
23405             iso1A2: "BN",
23406             iso1A3: "BRN",
23407             iso1N3: "096",
23408             wikidata: "Q921",
23409             nameEn: "Brunei",
23410             groups: ["Q36117", "035", "142", "UN"],
23411             driveSide: "left",
23412             callingCodes: ["673"]
23413           },
23414           geometry: {
23415             type: "MultiPolygon",
23416             coordinates: [[[[115.16236, 5.01011], [115.02521, 5.35005], [114.10166, 4.76112], [114.07448, 4.58441], [114.15813, 4.57], [114.26876, 4.49878], [114.32176, 4.34942], [114.32176, 4.2552], [114.4416, 4.27588], [114.49922, 4.13108], [114.64211, 4.00694], [114.78539, 4.12205], [114.88039, 4.4257], [114.83189, 4.42387], [114.77303, 4.72871], [114.8266, 4.75062], [114.88841, 4.81905], [114.96982, 4.81146], [114.99417, 4.88201], [115.05038, 4.90275], [115.02955, 4.82087], [115.02278, 4.74137], [115.04064, 4.63706], [115.07737, 4.53418], [115.09978, 4.39123], [115.31275, 4.30806], [115.36346, 4.33563], [115.2851, 4.42295], [115.27819, 4.63661], [115.20737, 4.8256], [115.15092, 4.87604], [115.16236, 5.01011]]]]
23417           }
23418         }, {
23419           type: "Feature",
23420           properties: {
23421             iso1A2: "BO",
23422             iso1A3: "BOL",
23423             iso1N3: "068",
23424             wikidata: "Q750",
23425             nameEn: "Bolivia",
23426             groups: ["005", "419", "019", "UN"],
23427             callingCodes: ["591"]
23428           },
23429           geometry: {
23430             type: "MultiPolygon",
23431             coordinates: [[[[-63.90248, -12.52544], [-64.22539, -12.45267], [-64.30708, -12.46398], [-64.99778, -11.98604], [-65.30027, -11.48749], [-65.28141, -10.86289], [-65.35402, -10.78685], [-65.37923, -10.35141], [-65.29019, -9.86253], [-65.40615, -9.63894], [-65.56244, -9.84266], [-65.68343, -9.75323], [-67.17784, -10.34016], [-68.71533, -11.14749], [-68.7651, -11.0496], [-68.75179, -11.03688], [-68.75265, -11.02383], [-68.74802, -11.00891], [-69.42792, -10.93451], [-69.47839, -10.95254], [-69.57156, -10.94555], [-68.98115, -11.8979], [-68.65044, -12.50689], [-68.85615, -12.87769], [-68.8864, -13.40792], [-69.05265, -13.68546], [-68.88135, -14.18639], [-69.36254, -14.94634], [-69.14856, -15.23478], [-69.40336, -15.61358], [-69.20291, -16.16668], [-69.09986, -16.22693], [-68.96238, -16.194], [-68.79464, -16.33272], [-68.98358, -16.42165], [-69.04027, -16.57214], [-69.00853, -16.66769], [-69.16896, -16.72233], [-69.62883, -17.28142], [-69.46863, -17.37466], [-69.46897, -17.4988], [-69.46623, -17.60518], [-69.34126, -17.72753], [-69.28671, -17.94844], [-69.07496, -18.03715], [-69.14807, -18.16893], [-69.07432, -18.28259], [-68.94987, -18.93302], [-68.87082, -19.06003], [-68.80602, -19.08355], [-68.61989, -19.27584], [-68.41218, -19.40499], [-68.66761, -19.72118], [-68.54611, -19.84651], [-68.57132, -20.03134], [-68.74273, -20.08817], [-68.7276, -20.46178], [-68.44023, -20.62701], [-68.55383, -20.7355], [-68.53957, -20.91542], [-68.40403, -20.94562], [-68.18816, -21.28614], [-67.85114, -22.87076], [-67.54284, -22.89771], [-67.18382, -22.81525], [-66.7298, -22.23644], [-66.29714, -22.08741], [-66.24077, -21.77837], [-66.03836, -21.84829], [-66.04832, -21.9187], [-65.9261, -21.93335], [-65.7467, -22.10105], [-65.61166, -22.09504], [-65.58694, -22.09794], [-65.57743, -22.07675], [-65.47435, -22.08908], [-64.99524, -22.08255], [-64.90014, -22.12136], [-64.67174, -22.18957], [-64.58888, -22.25035], [-64.4176, -22.67692], [-64.35108, -22.73282], [-64.31489, -22.88824], [-64.22918, -22.55807], [-63.93287, -21.99934], [-63.70963, -21.99934], [-63.68113, -22.0544], [-63.66482, -21.99918], [-62.81124, -21.9987], [-62.8078, -22.12534], [-62.64455, -22.25091], [-62.2757, -21.06657], [-62.26883, -20.55311], [-61.93912, -20.10053], [-61.73723, -19.63958], [-60.00638, -19.2981], [-59.06965, -19.29148], [-58.23216, -19.80058], [-58.16225, -20.16193], [-57.8496, -19.98346], [-58.14215, -19.76276], [-57.78463, -19.03259], [-57.71113, -19.03161], [-57.69134, -19.00544], [-57.71995, -18.97546], [-57.71995, -18.89573], [-57.76764, -18.90087], [-57.56807, -18.25655], [-57.48237, -18.24219], [-57.69877, -17.8431], [-57.73949, -17.56095], [-57.90082, -17.44555], [-57.99661, -17.5273], [-58.32935, -17.28195], [-58.5058, -16.80958], [-58.30918, -16.3699], [-58.32431, -16.25861], [-58.41506, -16.32636], [-60.16069, -16.26479], [-60.23797, -15.50267], [-60.58224, -15.09887], [-60.23968, -15.09515], [-60.27887, -14.63021], [-60.46037, -14.22496], [-60.48053, -13.77981], [-61.05527, -13.50054], [-61.81151, -13.49564], [-63.76259, -12.42952], [-63.90248, -12.52544]]]]
23432           }
23433         }, {
23434           type: "Feature",
23435           properties: {
23436             iso1A2: "BQ",
23437             iso1A3: "BES",
23438             iso1N3: "535",
23439             wikidata: "Q27561",
23440             nameEn: "Caribbean Netherlands",
23441             country: "NL"
23442           },
23443           geometry: null
23444         }, {
23445           type: "Feature",
23446           properties: {
23447             iso1A2: "BR",
23448             iso1A3: "BRA",
23449             iso1N3: "076",
23450             wikidata: "Q155",
23451             nameEn: "Brazil",
23452             groups: ["005", "419", "019", "UN"],
23453             callingCodes: ["55"]
23454           },
23455           geometry: {
23456             type: "MultiPolygon",
23457             coordinates: [[[[-59.69361, 4.34069], [-59.78878, 4.45637], [-60.15953, 4.53456], [-60.04189, 4.69801], [-59.98129, 5.07097], [-60.20944, 5.28754], [-60.32352, 5.21299], [-60.73204, 5.20931], [-60.5802, 4.94312], [-60.86539, 4.70512], [-60.98303, 4.54167], [-61.15703, 4.49839], [-61.31457, 4.54167], [-61.29675, 4.44216], [-61.48569, 4.43149], [-61.54629, 4.2822], [-62.13094, 4.08309], [-62.44822, 4.18621], [-62.57656, 4.04754], [-62.74411, 4.03331], [-62.7655, 3.73099], [-62.98296, 3.59935], [-63.21111, 3.96219], [-63.4464, 3.9693], [-63.42233, 3.89995], [-63.50611, 3.83592], [-63.67099, 4.01731], [-63.70218, 3.91417], [-63.86082, 3.94796], [-63.99183, 3.90172], [-64.14512, 4.12932], [-64.57648, 4.12576], [-64.72977, 4.28931], [-64.84028, 4.24665], [-64.48379, 3.7879], [-64.02908, 2.79797], [-64.0257, 2.48156], [-63.39114, 2.4317], [-63.39827, 2.16098], [-64.06135, 1.94722], [-64.08274, 1.64792], [-64.34654, 1.35569], [-64.38932, 1.5125], [-65.11657, 1.12046], [-65.57288, 0.62856], [-65.50158, 0.92086], [-65.6727, 1.01353], [-66.28507, 0.74585], [-66.85795, 1.22998], [-67.08222, 1.17441], [-67.15784, 1.80439], [-67.299, 1.87494], [-67.40488, 2.22258], [-67.9292, 1.82455], [-68.18632, 2.00091], [-68.26699, 1.83463], [-68.18128, 1.72881], [-69.38621, 1.70865], [-69.53746, 1.76408], [-69.83491, 1.69353], [-69.82987, 1.07864], [-69.26017, 1.06856], [-69.14422, 0.84172], [-69.20976, 0.57958], [-69.47696, 0.71065], [-70.04162, 0.55437], [-70.03658, -0.19681], [-69.603, -0.51947], [-69.59796, -0.75136], [-69.4215, -1.01853], [-69.43395, -1.42219], [-69.94708, -4.2431], [-70.00888, -4.37833], [-70.11305, -4.27281], [-70.19582, -4.3607], [-70.33236, -4.15214], [-70.77601, -4.15717], [-70.96814, -4.36915], [-71.87003, -4.51661], [-72.64391, -5.0391], [-72.83973, -5.14765], [-73.24579, -6.05764], [-73.12983, -6.43852], [-73.73986, -6.87919], [-73.77011, -7.28944], [-73.96938, -7.58465], [-73.65485, -7.77897], [-73.76576, -7.89884], [-72.92886, -9.04074], [-73.21498, -9.40904], [-72.72216, -9.41397], [-72.31883, -9.5184], [-72.14742, -9.98049], [-71.23394, -9.9668], [-70.53373, -9.42628], [-70.58453, -9.58303], [-70.55429, -9.76692], [-70.62487, -9.80666], [-70.64134, -11.0108], [-70.51395, -10.92249], [-70.38791, -11.07096], [-69.90896, -10.92744], [-69.57835, -10.94051], [-69.57156, -10.94555], [-69.47839, -10.95254], [-69.42792, -10.93451], [-68.74802, -11.00891], [-68.75265, -11.02383], [-68.75179, -11.03688], [-68.7651, -11.0496], [-68.71533, -11.14749], [-67.17784, -10.34016], [-65.68343, -9.75323], [-65.56244, -9.84266], [-65.40615, -9.63894], [-65.29019, -9.86253], [-65.37923, -10.35141], [-65.35402, -10.78685], [-65.28141, -10.86289], [-65.30027, -11.48749], [-64.99778, -11.98604], [-64.30708, -12.46398], [-64.22539, -12.45267], [-63.90248, -12.52544], [-63.76259, -12.42952], [-61.81151, -13.49564], [-61.05527, -13.50054], [-60.48053, -13.77981], [-60.46037, -14.22496], [-60.27887, -14.63021], [-60.23968, -15.09515], [-60.58224, -15.09887], [-60.23797, -15.50267], [-60.16069, -16.26479], [-58.41506, -16.32636], [-58.32431, -16.25861], [-58.30918, -16.3699], [-58.5058, -16.80958], [-58.32935, -17.28195], [-57.99661, -17.5273], [-57.90082, -17.44555], [-57.73949, -17.56095], [-57.69877, -17.8431], [-57.48237, -18.24219], [-57.56807, -18.25655], [-57.76764, -18.90087], [-57.71995, -18.89573], [-57.71995, -18.97546], [-57.69134, -19.00544], [-57.71113, -19.03161], [-57.78463, -19.03259], [-58.14215, -19.76276], [-57.8496, -19.98346], [-58.16225, -20.16193], [-57.84536, -20.93155], [-57.93492, -21.65505], [-57.88239, -21.6868], [-57.94642, -21.73799], [-57.98625, -22.09157], [-56.6508, -22.28387], [-56.5212, -22.11556], [-56.45893, -22.08072], [-56.23206, -22.25347], [-55.8331, -22.29008], [-55.74941, -22.46436], [-55.741, -22.52018], [-55.72366, -22.5519], [-55.6986, -22.56268], [-55.68742, -22.58407], [-55.62493, -22.62765], [-55.63849, -22.95122], [-55.5446, -23.22811], [-55.52288, -23.2595], [-55.5555, -23.28237], [-55.43585, -23.87157], [-55.44117, -23.9185], [-55.41784, -23.9657], [-55.12292, -23.99669], [-55.0518, -23.98666], [-55.02691, -23.97317], [-54.6238, -23.83078], [-54.32807, -24.01865], [-54.28207, -24.07305], [-54.4423, -25.13381], [-54.62033, -25.46026], [-54.60196, -25.48397], [-54.59509, -25.53696], [-54.59398, -25.59224], [-54.5502, -25.58915], [-54.52926, -25.62846], [-53.90831, -25.55513], [-53.83691, -25.94849], [-53.73511, -26.04211], [-53.73086, -26.05842], [-53.7264, -26.0664], [-53.73391, -26.07006], [-53.73968, -26.10012], [-53.65018, -26.19501], [-53.65237, -26.23289], [-53.63739, -26.2496], [-53.63881, -26.25075], [-53.64632, -26.24798], [-53.64186, -26.25976], [-53.64505, -26.28089], [-53.68269, -26.33359], [-53.73372, -26.6131], [-53.80144, -27.09844], [-54.15978, -27.2889], [-54.19062, -27.27639], [-54.19268, -27.30751], [-54.41888, -27.40882], [-54.50416, -27.48232], [-54.67657, -27.57214], [-54.90159, -27.63132], [-54.90805, -27.73149], [-55.1349, -27.89759], [-55.16872, -27.86224], [-55.33303, -27.94661], [-55.6262, -28.17124], [-55.65418, -28.18304], [-56.01729, -28.51223], [-56.00458, -28.60421], [-56.05265, -28.62651], [-56.54171, -29.11447], [-56.57295, -29.11357], [-56.62789, -29.18073], [-56.81251, -29.48154], [-57.09386, -29.74211], [-57.65132, -30.19229], [-57.22502, -30.26121], [-56.90236, -30.02578], [-56.49267, -30.39471], [-56.4795, -30.3899], [-56.4619, -30.38457], [-55.87388, -31.05053], [-55.58866, -30.84117], [-55.5634, -30.8686], [-55.55373, -30.8732], [-55.55218, -30.88193], [-55.54572, -30.89051], [-55.53431, -30.89714], [-55.53276, -30.90218], [-55.52712, -30.89997], [-55.51862, -30.89828], [-55.50841, -30.9027], [-55.50821, -30.91349], [-54.17384, -31.86168], [-53.76024, -32.0751], [-53.39572, -32.58596], [-53.37671, -32.57005], [-53.1111, -32.71147], [-53.53459, -33.16843], [-53.52794, -33.68908], [-53.44031, -33.69344], [-53.39593, -33.75169], [-53.37138, -33.74313], [-52.83257, -34.01481], [-28.34015, -20.99094], [-28.99601, 1.86593], [-51.35485, 4.8383], [-51.63798, 4.51394], [-51.61983, 4.14596], [-51.79599, 3.89336], [-51.82312, 3.85825], [-51.85573, 3.83427], [-52.31787, 3.17896], [-52.6906, 2.37298], [-52.96539, 2.1881], [-53.78743, 2.34412], [-54.16286, 2.10779], [-54.6084, 2.32856], [-55.01919, 2.564], [-55.71493, 2.40342], [-55.96292, 2.53188], [-56.13054, 2.27723], [-55.92159, 2.05236], [-55.89863, 1.89861], [-55.99278, 1.83137], [-56.47045, 1.95135], [-56.7659, 1.89509], [-57.07092, 1.95304], [-57.09109, 2.01854], [-57.23981, 1.95808], [-57.35073, 1.98327], [-57.55743, 1.69605], [-57.77281, 1.73344], [-57.97336, 1.64566], [-58.01873, 1.51966], [-58.33887, 1.58014], [-58.4858, 1.48399], [-58.53571, 1.29154], [-58.84229, 1.17749], [-58.92072, 1.31293], [-59.25583, 1.40559], [-59.74066, 1.87596], [-59.7264, 2.27497], [-59.91177, 2.36759], [-59.99733, 2.92312], [-59.79769, 3.37162], [-59.86899, 3.57089], [-59.51963, 3.91951], [-59.73353, 4.20399], [-59.69361, 4.34069]]]]
23458           }
23459         }, {
23460           type: "Feature",
23461           properties: {
23462             iso1A2: "BS",
23463             iso1A3: "BHS",
23464             iso1N3: "044",
23465             wikidata: "Q778",
23466             nameEn: "The Bahamas",
23467             groups: ["029", "003", "419", "019", "UN"],
23468             driveSide: "left",
23469             roadSpeedUnit: "mph",
23470             callingCodes: ["1 242"]
23471           },
23472           geometry: {
23473             type: "MultiPolygon",
23474             coordinates: [[[[-72.98446, 20.4801], [-71.70065, 25.7637], [-78.91214, 27.76553], [-80.65727, 23.71953], [-72.98446, 20.4801]]]]
23475           }
23476         }, {
23477           type: "Feature",
23478           properties: {
23479             iso1A2: "BT",
23480             iso1A3: "BTN",
23481             iso1N3: "064",
23482             wikidata: "Q917",
23483             nameEn: "Bhutan",
23484             groups: ["034", "142", "UN"],
23485             driveSide: "left",
23486             callingCodes: ["975"]
23487           },
23488           geometry: {
23489             type: "MultiPolygon",
23490             coordinates: [[[[91.6469, 27.76358], [91.5629, 27.84823], [91.48973, 27.93903], [91.46327, 28.0064], [91.25779, 28.07509], [91.20019, 27.98715], [90.69894, 28.07784], [90.58842, 28.02838], [90.13387, 28.19178], [89.79762, 28.23979], [89.59525, 28.16433], [89.12825, 27.62502], [89.0582, 27.60985], [88.97213, 27.51671], [88.95355, 27.4106], [89.00216, 27.32532], [88.96947, 27.30319], [88.93678, 27.33777], [88.91901, 27.32483], [88.74219, 27.144], [88.86984, 27.10937], [88.8714, 26.97488], [88.92301, 26.99286], [88.95807, 26.92668], [89.09554, 26.89089], [89.12825, 26.81661], [89.1926, 26.81329], [89.37913, 26.86224], [89.38319, 26.85963], [89.3901, 26.84225], [89.42349, 26.83727], [89.63369, 26.74402], [89.86124, 26.73307], [90.04535, 26.72422], [90.30402, 26.85098], [90.39271, 26.90704], [90.48504, 26.8594], [90.67715, 26.77215], [91.50067, 26.79223], [91.83181, 26.87318], [92.05523, 26.8692], [92.11863, 26.893], [92.03457, 27.07334], [92.04702, 27.26861], [92.12019, 27.27829], [92.01132, 27.47352], [91.65007, 27.48287], [91.55819, 27.6144], [91.6469, 27.76358]]]]
23491           }
23492         }, {
23493           type: "Feature",
23494           properties: {
23495             iso1A2: "BV",
23496             iso1A3: "BVT",
23497             iso1N3: "074",
23498             wikidata: "Q23408",
23499             nameEn: "Bouvet Island",
23500             country: "NO",
23501             groups: ["005", "419", "019", "UN"]
23502           },
23503           geometry: {
23504             type: "MultiPolygon",
23505             coordinates: [[[[4.54042, -54.0949], [2.28941, -54.13089], [3.35353, -55.17558], [4.54042, -54.0949]]]]
23506           }
23507         }, {
23508           type: "Feature",
23509           properties: {
23510             iso1A2: "BW",
23511             iso1A3: "BWA",
23512             iso1N3: "072",
23513             wikidata: "Q963",
23514             nameEn: "Botswana",
23515             groups: ["018", "202", "002", "UN"],
23516             driveSide: "left",
23517             callingCodes: ["267"]
23518           },
23519           geometry: {
23520             type: "MultiPolygon",
23521             coordinates: [[[[25.26433, -17.79571], [25.16882, -17.78253], [25.05895, -17.84452], [24.95586, -17.79674], [24.73364, -17.89338], [24.71887, -17.9218], [24.6303, -17.9863], [24.57485, -18.07151], [24.40577, -17.95726], [24.19416, -18.01919], [23.61088, -18.4881], [23.29618, -17.99855], [23.0996, -18.00075], [21.45556, -18.31795], [20.99904, -18.31743], [20.99751, -22.00026], [19.99912, -21.99991], [19.99817, -24.76768], [20.02809, -24.78725], [20.03678, -24.81004], [20.29826, -24.94869], [20.64795, -25.47827], [20.86081, -26.14892], [20.61754, -26.4692], [20.63275, -26.78181], [20.68596, -26.9039], [20.87031, -26.80047], [21.13353, -26.86661], [21.37869, -26.82083], [21.69322, -26.86152], [21.7854, -26.79199], [21.77114, -26.69015], [21.83291, -26.65959], [21.90703, -26.66808], [22.06192, -26.61882], [22.21206, -26.3773], [22.41921, -26.23078], [22.56365, -26.19668], [22.70808, -25.99186], [22.86012, -25.50572], [23.03497, -25.29971], [23.47588, -25.29971], [23.9244, -25.64286], [24.18287, -25.62916], [24.36531, -25.773], [24.44703, -25.73021], [24.67319, -25.81749], [24.8946, -25.80723], [25.01718, -25.72507], [25.12266, -25.75931], [25.33076, -25.76616], [25.58543, -25.6343], [25.6643, -25.4491], [25.69661, -25.29284], [25.72702, -25.25503], [25.88571, -24.87802], [25.84295, -24.78661], [25.8515, -24.75727], [26.39409, -24.63468], [26.46346, -24.60358], [26.51667, -24.47219], [26.84165, -24.24885], [26.99749, -23.65486], [27.33768, -23.40917], [27.52393, -23.37952], [27.6066, -23.21894], [27.74154, -23.2137], [27.93539, -23.04941], [27.93729, -22.96194], [28.04752, -22.90243], [28.04562, -22.8394], [28.34874, -22.5694], [28.63287, -22.55887], [28.91889, -22.44299], [29.0151, -22.22907], [29.10881, -22.21202], [29.15268, -22.21399], [29.18974, -22.18599], [29.21955, -22.17771], [29.37703, -22.19581], [29.3533, -22.18363], [29.24648, -22.05967], [29.1974, -22.07472], [29.14501, -22.07275], [29.08495, -22.04867], [29.04108, -22.00563], [29.02191, -21.95665], [29.02191, -21.90647], [29.04023, -21.85864], [29.07763, -21.81877], [28.58114, -21.63455], [28.49942, -21.66634], [28.29416, -21.59037], [28.01669, -21.57624], [27.91407, -21.31621], [27.69171, -21.08409], [27.72972, -20.51735], [27.69361, -20.48531], [27.28865, -20.49873], [27.29831, -20.28935], [27.21278, -20.08244], [26.72246, -19.92707], [26.17227, -19.53709], [25.96226, -19.08152], [25.99837, -19.02943], [25.94326, -18.90362], [25.82353, -18.82808], [25.79217, -18.6355], [25.68859, -18.56165], [25.53465, -18.39041], [25.39972, -18.12691], [25.31799, -18.07091], [25.23909, -17.90832], [25.26433, -17.79571]]]]
23522           }
23523         }, {
23524           type: "Feature",
23525           properties: {
23526             iso1A2: "BY",
23527             iso1A3: "BLR",
23528             iso1N3: "112",
23529             wikidata: "Q184",
23530             nameEn: "Belarus",
23531             groups: ["151", "150", "UN"],
23532             callingCodes: ["375"]
23533           },
23534           geometry: {
23535             type: "MultiPolygon",
23536             coordinates: [[[[28.15217, 56.16964], [27.97865, 56.11849], [27.63065, 55.89687], [27.61683, 55.78558], [27.3541, 55.8089], [27.27804, 55.78299], [27.1559, 55.85032], [26.97153, 55.8102], [26.87448, 55.7172], [26.76872, 55.67658], [26.71802, 55.70645], [26.64888, 55.70515], [26.63231, 55.67968], [26.63167, 55.57887], [26.55094, 55.5093], [26.5522, 55.40277], [26.44937, 55.34832], [26.5709, 55.32572], [26.6714, 55.33902], [26.80929, 55.31642], [26.83266, 55.30444], [26.835, 55.28182], [26.73017, 55.24226], [26.72983, 55.21788], [26.68075, 55.19787], [26.69243, 55.16718], [26.54753, 55.14181], [26.51481, 55.16051], [26.46249, 55.12814], [26.35121, 55.1525], [26.30628, 55.12536], [26.23202, 55.10439], [26.26941, 55.08032], [26.20397, 54.99729], [26.13386, 54.98924], [26.05907, 54.94631], [25.99129, 54.95705], [25.89462, 54.93438], [25.74122, 54.80108], [25.75977, 54.57252], [25.68045, 54.5321], [25.64813, 54.48704], [25.62203, 54.4656], [25.63371, 54.42075], [25.5376, 54.33158], [25.55425, 54.31591], [25.68513, 54.31727], [25.78553, 54.23327], [25.78563, 54.15747], [25.71084, 54.16704], [25.64875, 54.1259], [25.54724, 54.14925], [25.51452, 54.17799], [25.56823, 54.25212], [25.509, 54.30267], [25.35559, 54.26544], [25.22705, 54.26271], [25.19199, 54.219], [25.0728, 54.13419], [24.991, 54.14241], [24.96894, 54.17589], [24.77131, 54.11091], [24.85311, 54.02862], [24.74279, 53.96663], [24.69185, 53.96543], [24.69652, 54.01901], [24.62275, 54.00217], [24.44411, 53.90076], [24.34128, 53.90076], [24.19638, 53.96405], [23.98837, 53.92554], [23.95098, 53.9613], [23.81309, 53.94205], [23.80543, 53.89558], [23.71726, 53.93379], [23.61677, 53.92691], [23.51284, 53.95052], [23.62004, 53.60942], [23.81995, 53.24131], [23.85657, 53.22923], [23.91393, 53.16469], [23.87548, 53.0831], [23.92184, 53.02079], [23.94689, 52.95919], [23.91805, 52.94016], [23.93763, 52.71332], [23.73615, 52.6149], [23.58296, 52.59868], [23.45112, 52.53774], [23.34141, 52.44845], [23.18196, 52.28812], [23.20071, 52.22848], [23.47859, 52.18215], [23.54314, 52.12148], [23.61, 52.11264], [23.64066, 52.07626], [23.68733, 51.9906], [23.61523, 51.92066], [23.62691, 51.78208], [23.53198, 51.74298], [23.57053, 51.55938], [23.56236, 51.53673], [23.62751, 51.50512], [23.6736, 51.50255], [23.60906, 51.62122], [23.7766, 51.66809], [23.91118, 51.63316], [23.8741, 51.59734], [23.99907, 51.58369], [24.13075, 51.66979], [24.3163, 51.75063], [24.29021, 51.80841], [24.37123, 51.88222], [24.98784, 51.91273], [25.20228, 51.97143], [25.46163, 51.92205], [25.73673, 51.91973], [25.80574, 51.94556], [25.83217, 51.92587], [26.00408, 51.92967], [26.19084, 51.86781], [26.39367, 51.87315], [26.46962, 51.80501], [26.69759, 51.82284], [26.80043, 51.75777], [26.9489, 51.73788], [26.99422, 51.76933], [27.20602, 51.77291], [27.20948, 51.66713], [27.26613, 51.65957], [27.24828, 51.60161], [27.47212, 51.61184], [27.51058, 51.5854], [27.55727, 51.63486], [27.71932, 51.60672], [27.67125, 51.50854], [27.76052, 51.47604], [27.85253, 51.62293], [27.91844, 51.61952], [27.95827, 51.56065], [28.10658, 51.57857], [28.23452, 51.66988], [28.37592, 51.54505], [28.47051, 51.59734], [28.64429, 51.5664], [28.69161, 51.44695], [28.73143, 51.46236], [28.75615, 51.41442], [28.78224, 51.45294], [28.76027, 51.48802], [28.81795, 51.55552], [28.95528, 51.59222], [28.99098, 51.56833], [29.1187, 51.65872], [29.16402, 51.64679], [29.20659, 51.56918], [29.25603, 51.57089], [29.25191, 51.49828], [29.32881, 51.37843], [29.42357, 51.4187], [29.49773, 51.39814], [29.54372, 51.48372], [29.7408, 51.53417], [29.77376, 51.4461], [30.17888, 51.51025], [30.34642, 51.42555], [30.36153, 51.33984], [30.56203, 51.25655], [30.64992, 51.35014], [30.51946, 51.59649], [30.68804, 51.82806], [30.76443, 51.89739], [30.90897, 52.00699], [30.95589, 52.07775], [31.13332, 52.1004], [31.25142, 52.04131], [31.38326, 52.12991], [31.7822, 52.11406], [31.77877, 52.18636], [31.6895, 52.1973], [31.70735, 52.26711], [31.57971, 52.32146], [31.62084, 52.33849], [31.61397, 52.48843], [31.56316, 52.51518], [31.63869, 52.55361], [31.50406, 52.69707], [31.57277, 52.71613], [31.592, 52.79011], [31.35667, 52.97854], [31.24147, 53.031], [31.32283, 53.04101], [31.33519, 53.08805], [31.3915, 53.09712], [31.36403, 53.13504], [31.40523, 53.21406], [31.56316, 53.19432], [31.62496, 53.22886], [31.787, 53.18033], [31.82373, 53.10042], [32.15368, 53.07594], [32.40773, 53.18856], [32.51725, 53.28431], [32.73257, 53.33494], [32.74968, 53.45597], [32.47777, 53.5548], [32.40499, 53.6656], [32.50112, 53.68594], [32.45717, 53.74039], [32.36663, 53.7166], [32.12621, 53.81586], [31.89137, 53.78099], [31.77028, 53.80015], [31.85019, 53.91801], [31.88744, 54.03653], [31.89599, 54.0837], [31.57002, 54.14535], [31.30791, 54.25315], [31.3177, 54.34067], [31.22945, 54.46585], [31.08543, 54.50361], [31.21399, 54.63113], [31.19339, 54.66947], [30.99187, 54.67046], [30.98226, 54.68872], [31.0262, 54.70698], [30.97127, 54.71967], [30.95479, 54.74346], [30.75165, 54.80699], [30.8264, 54.90062], [30.81759, 54.94064], [30.93144, 54.9585], [30.95754, 54.98609], [30.9081, 55.02232], [30.94243, 55.03964], [31.00972, 55.02783], [31.02071, 55.06167], [30.97369, 55.17134], [30.87944, 55.28223], [30.81946, 55.27931], [30.8257, 55.3313], [30.93144, 55.3914], [30.90123, 55.46621], [30.95204, 55.50667], [30.93419, 55.6185], [30.86003, 55.63169], [30.7845, 55.58514], [30.72957, 55.66268], [30.67464, 55.64176], [30.63344, 55.73079], [30.51037, 55.76568], [30.51346, 55.78982], [30.48257, 55.81066], [30.30987, 55.83592], [30.27776, 55.86819], [30.12136, 55.8358], [29.97975, 55.87281], [29.80672, 55.79569], [29.61446, 55.77716], [29.51283, 55.70294], [29.3604, 55.75862], [29.44692, 55.95978], [29.21717, 55.98971], [29.08299, 56.03427], [28.73418, 55.97131], [28.63668, 56.07262], [28.68337, 56.10173], [28.5529, 56.11705], [28.43068, 56.09407], [28.37987, 56.11399], [28.36888, 56.05805], [28.30571, 56.06035], [28.15217, 56.16964]]]]
23537           }
23538         }, {
23539           type: "Feature",
23540           properties: {
23541             iso1A2: "BZ",
23542             iso1A3: "BLZ",
23543             iso1N3: "084",
23544             wikidata: "Q242",
23545             nameEn: "Belize",
23546             groups: ["013", "003", "419", "019", "UN"],
23547             roadSpeedUnit: "mph",
23548             callingCodes: ["501"]
23549           },
23550           geometry: {
23551             type: "MultiPolygon",
23552             coordinates: [[[[-88.3268, 18.49048], [-88.48242, 18.49164], [-88.71505, 18.0707], [-88.8716, 17.89535], [-89.03839, 18.0067], [-89.15105, 17.95104], [-89.14985, 17.81563], [-89.15025, 17.04813], [-89.22683, 15.88619], [-89.17418, 15.90898], [-89.02415, 15.9063], [-88.95358, 15.88698], [-88.40779, 16.09624], [-86.92368, 17.61462], [-87.84815, 18.18511], [-87.85693, 18.18266], [-87.86657, 18.19971], [-87.87604, 18.18313], [-87.90671, 18.15213], [-88.03165, 18.16657], [-88.03238, 18.41778], [-88.26593, 18.47617], [-88.29909, 18.47591], [-88.3268, 18.49048]]]]
23553           }
23554         }, {
23555           type: "Feature",
23556           properties: {
23557             iso1A2: "CA",
23558             iso1A3: "CAN",
23559             iso1N3: "124",
23560             wikidata: "Q16",
23561             nameEn: "Canada",
23562             groups: ["021", "003", "019", "UN"],
23563             callingCodes: ["1"]
23564           },
23565           geometry: {
23566             type: "MultiPolygon",
23567             coordinates: [[[[-67.20349, 45.1722], [-67.19603, 45.16771], [-67.15965, 45.16179], [-67.11316, 45.11176], [-67.0216, 44.95333], [-66.96824, 44.90965], [-66.98249, 44.87071], [-66.96824, 44.83078], [-66.93432, 44.82597], [-67.16117, 44.20069], [-61.98255, 37.34815], [-56.27503, 47.39728], [-53.12387, 41.40385], [-46.37635, 57.3249], [-77.52957, 77.23408], [-68.21821, 80.48551], [-49.33696, 84.57952], [-140.97446, 84.39275], [-141.00116, 60.30648], [-140.5227, 60.22077], [-140.45648, 60.30919], [-139.98024, 60.18027], [-139.68991, 60.33693], [-139.05831, 60.35205], [-139.20603, 60.08896], [-139.05365, 59.99655], [-138.71149, 59.90728], [-138.62145, 59.76431], [-137.60623, 59.24465], [-137.4925, 58.89415], [-136.82619, 59.16198], [-136.52365, 59.16752], [-136.47323, 59.46617], [-136.33727, 59.44466], [-136.22381, 59.55526], [-136.31566, 59.59083], [-135.48007, 59.79937], [-135.03069, 59.56208], [-135.00267, 59.28745], [-134.7047, 59.2458], [-134.55699, 59.1297], [-134.48059, 59.13231], [-134.27175, 58.8634], [-133.84645, 58.73543], [-133.38523, 58.42773], [-131.8271, 56.62247], [-130.77769, 56.36185], [-130.33965, 56.10849], [-130.10173, 56.12178], [-130.00093, 56.00325], [-130.00857, 55.91344], [-130.15373, 55.74895], [-129.97513, 55.28029], [-130.08035, 55.21556], [-130.18765, 55.07744], [-130.27203, 54.97174], [-130.44184, 54.85377], [-130.64499, 54.76912], [-130.61931, 54.70835], [-133.92876, 54.62289], [-133.36909, 48.51151], [-125.03842, 48.53282], [-123.50039, 48.21223], [-123.15614, 48.35395], [-123.26565, 48.6959], [-123.0093, 48.76586], [-123.0093, 48.83186], [-123.32163, 49.00419], [-95.15355, 48.9996], [-95.15357, 49.384], [-95.12903, 49.37056], [-95.05825, 49.35311], [-95.01419, 49.35647], [-94.99532, 49.36579], [-94.95681, 49.37035], [-94.85381, 49.32492], [-94.8159, 49.32299], [-94.82487, 49.29483], [-94.77355, 49.11998], [-94.75017, 49.09931], [-94.687, 48.84077], [-94.70087, 48.8339], [-94.70486, 48.82365], [-94.69669, 48.80918], [-94.69335, 48.77883], [-94.58903, 48.71803], [-94.54885, 48.71543], [-94.53826, 48.70216], [-94.44258, 48.69223], [-94.4174, 48.71049], [-94.27153, 48.70232], [-94.25172, 48.68404], [-94.25104, 48.65729], [-94.23215, 48.65202], [-93.85769, 48.63284], [-93.83288, 48.62745], [-93.80676, 48.58232], [-93.80939, 48.52439], [-93.79267, 48.51631], [-93.66382, 48.51845], [-93.47022, 48.54357], [-93.44472, 48.59147], [-93.40693, 48.60948], [-93.39758, 48.60364], [-93.3712, 48.60599], [-93.33946, 48.62787], [-93.25391, 48.64266], [-92.94973, 48.60866], [-92.7287, 48.54005], [-92.6342, 48.54133], [-92.62747, 48.50278], [-92.69927, 48.49573], [-92.71323, 48.46081], [-92.65606, 48.43471], [-92.50712, 48.44921], [-92.45588, 48.40624], [-92.48147, 48.36609], [-92.37185, 48.22259], [-92.27167, 48.25046], [-92.30939, 48.31251], [-92.26662, 48.35651], [-92.202, 48.35252], [-92.14732, 48.36578], [-92.05339, 48.35958], [-91.98929, 48.25409], [-91.86125, 48.21278], [-91.71231, 48.19875], [-91.70451, 48.11805], [-91.55649, 48.10611], [-91.58025, 48.04339], [-91.45829, 48.07454], [-91.43248, 48.04912], [-91.25025, 48.08522], [-91.08016, 48.18096], [-90.87588, 48.2484], [-90.75045, 48.09143], [-90.56444, 48.12184], [-90.56312, 48.09488], [-90.07418, 48.11043], [-89.89974, 47.98109], [-89.77248, 48.02607], [-89.57972, 48.00023], [-89.48837, 48.01412], [-88.37033, 48.30586], [-84.85871, 46.88881], [-84.55635, 46.45974], [-84.47607, 46.45225], [-84.4481, 46.48972], [-84.42101, 46.49853], [-84.34174, 46.50683], [-84.29893, 46.49127], [-84.26351, 46.49508], [-84.2264, 46.53337], [-84.1945, 46.54061], [-84.17723, 46.52753], [-84.12885, 46.53068], [-84.11196, 46.50248], [-84.13451, 46.39218], [-84.11254, 46.32329], [-84.11615, 46.2681], [-84.09756, 46.25512], [-84.1096, 46.23987], [-83.95399, 46.05634], [-83.90453, 46.05922], [-83.83329, 46.12169], [-83.57017, 46.105], [-83.43746, 45.99749], [-83.59589, 45.82131], [-82.48419, 45.30225], [-82.42469, 42.992], [-82.4146, 42.97626], [-82.4253, 42.95423], [-82.45331, 42.93139], [-82.4826, 42.8068], [-82.46613, 42.76615], [-82.51063, 42.66025], [-82.51858, 42.611], [-82.57583, 42.5718], [-82.58873, 42.54984], [-82.64242, 42.55594], [-82.82964, 42.37355], [-83.02253, 42.33045], [-83.07837, 42.30978], [-83.09837, 42.28877], [-83.12724, 42.2376], [-83.14962, 42.04089], [-83.11184, 41.95671], [-82.67862, 41.67615], [-78.93684, 42.82887], [-78.90712, 42.89733], [-78.90905, 42.93022], [-78.93224, 42.95229], [-78.96312, 42.95509], [-78.98126, 42.97], [-79.02074, 42.98444], [-79.02424, 43.01983], [-78.99941, 43.05612], [-79.01055, 43.06659], [-79.07486, 43.07845], [-79.05671, 43.10937], [-79.06881, 43.12029], [-79.0427, 43.13934], [-79.04652, 43.16396], [-79.05384, 43.17418], [-79.05002, 43.20133], [-79.05544, 43.21224], [-79.05512, 43.25375], [-79.06921, 43.26183], [-79.25796, 43.54052], [-76.79706, 43.63099], [-76.43859, 44.09393], [-76.35324, 44.13493], [-76.31222, 44.19894], [-76.244, 44.19643], [-76.1664, 44.23051], [-76.16285, 44.28262], [-76.00018, 44.34896], [-75.95947, 44.34463], [-75.8217, 44.43176], [-75.76813, 44.51537], [-75.41441, 44.76614], [-75.2193, 44.87821], [-75.01363, 44.95608], [-74.99101, 44.98051], [-74.8447, 45.00606], [-74.66689, 45.00646], [-74.32699, 44.99029], [-73.35025, 45.00942], [-71.50067, 45.01357], [-71.48735, 45.07784], [-71.42778, 45.12624], [-71.40364, 45.21382], [-71.44252, 45.2361], [-71.37133, 45.24624], [-71.29371, 45.29996], [-71.22338, 45.25184], [-71.19723, 45.25438], [-71.14568, 45.24128], [-71.08364, 45.30623], [-71.01866, 45.31573], [-71.0107, 45.34819], [-70.95193, 45.33895], [-70.91169, 45.29849], [-70.89864, 45.2398], [-70.84816, 45.22698], [-70.80236, 45.37444], [-70.82638, 45.39828], [-70.78372, 45.43269], [-70.65383, 45.37592], [-70.62518, 45.42286], [-70.72651, 45.49771], [-70.68516, 45.56964], [-70.54019, 45.67291], [-70.38934, 45.73215], [-70.41523, 45.79497], [-70.25976, 45.89675], [-70.24694, 45.95138], [-70.31025, 45.96424], [-70.23855, 46.1453], [-70.29078, 46.18832], [-70.18547, 46.35357], [-70.05812, 46.41768], [-69.99966, 46.69543], [-69.22119, 47.46461], [-69.05148, 47.42012], [-69.05073, 47.30076], [-69.05039, 47.2456], [-68.89222, 47.1807], [-68.70125, 47.24399], [-68.60575, 47.24659], [-68.57914, 47.28431], [-68.38332, 47.28723], [-68.37458, 47.35851], [-68.23244, 47.35712], [-67.94843, 47.1925], [-67.87993, 47.10377], [-67.78578, 47.06473], [-67.78111, 45.9392], [-67.75196, 45.91814], [-67.80961, 45.87531], [-67.75654, 45.82324], [-67.80653, 45.80022], [-67.80705, 45.69528], [-67.6049, 45.60725], [-67.43815, 45.59162], [-67.42144, 45.50584], [-67.50578, 45.48971], [-67.42394, 45.37969], [-67.48201, 45.27351], [-67.34927, 45.122], [-67.29754, 45.14865], [-67.29748, 45.18173], [-67.27039, 45.1934], [-67.22751, 45.16344], [-67.20349, 45.1722]]]]
23568           }
23569         }, {
23570           type: "Feature",
23571           properties: {
23572             iso1A2: "CC",
23573             iso1A3: "CCK",
23574             iso1N3: "166",
23575             wikidata: "Q36004",
23576             nameEn: "Cocos (Keeling) Islands",
23577             country: "AU",
23578             groups: ["053", "009", "UN"],
23579             driveSide: "left",
23580             callingCodes: ["61"]
23581           },
23582           geometry: {
23583             type: "MultiPolygon",
23584             coordinates: [[[[96.61846, -10.82438], [96.02343, -12.68334], [97.93979, -12.33309], [96.61846, -10.82438]]]]
23585           }
23586         }, {
23587           type: "Feature",
23588           properties: {
23589             iso1A2: "CD",
23590             iso1A3: "COD",
23591             iso1N3: "180",
23592             wikidata: "Q974",
23593             nameEn: "Democratic Republic of the Congo",
23594             aliases: ["ZR"],
23595             groups: ["017", "202", "002", "UN"],
23596             callingCodes: ["243"]
23597           },
23598           geometry: {
23599             type: "MultiPolygon",
23600             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]]]]
23601           }
23602         }, {
23603           type: "Feature",
23604           properties: {
23605             iso1A2: "CF",
23606             iso1A3: "CAF",
23607             iso1N3: "140",
23608             wikidata: "Q929",
23609             nameEn: "Central African Republic",
23610             groups: ["017", "202", "002", "UN"],
23611             callingCodes: ["236"]
23612           },
23613           geometry: {
23614             type: "MultiPolygon",
23615             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]]]]
23616           }
23617         }, {
23618           type: "Feature",
23619           properties: {
23620             iso1A2: "CG",
23621             iso1A3: "COG",
23622             iso1N3: "178",
23623             wikidata: "Q971",
23624             nameEn: "Republic of the Congo",
23625             groups: ["017", "202", "002", "UN"],
23626             callingCodes: ["242"]
23627           },
23628           geometry: {
23629             type: "MultiPolygon",
23630             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]]]]
23631           }
23632         }, {
23633           type: "Feature",
23634           properties: {
23635             iso1A2: "CH",
23636             iso1A3: "CHE",
23637             iso1N3: "756",
23638             wikidata: "Q39",
23639             nameEn: "Switzerland",
23640             groups: ["155", "150", "UN"],
23641             callingCodes: ["41"]
23642           },
23643           geometry: {
23644             type: "MultiPolygon",
23645             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]]]]
23646           }
23647         }, {
23648           type: "Feature",
23649           properties: {
23650             iso1A2: "CI",
23651             iso1A3: "CIV",
23652             iso1N3: "384",
23653             wikidata: "Q1008",
23654             nameEn: "C\xF4te d'Ivoire",
23655             groups: ["011", "202", "002", "UN"],
23656             callingCodes: ["225"]
23657           },
23658           geometry: {
23659             type: "MultiPolygon",
23660             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]]]]
23661           }
23662         }, {
23663           type: "Feature",
23664           properties: {
23665             iso1A2: "CK",
23666             iso1A3: "COK",
23667             iso1N3: "184",
23668             wikidata: "Q26988",
23669             nameEn: "Cook Islands",
23670             country: "NZ",
23671             groups: ["061", "009", "UN"],
23672             driveSide: "left",
23673             callingCodes: ["682"]
23674           },
23675           geometry: {
23676             type: "MultiPolygon",
23677             coordinates: [[[[-168.15106, -10.26955], [-156.45576, -31.75456], [-156.48634, -15.52824], [-156.50903, -7.4975], [-168.15106, -10.26955]]]]
23678           }
23679         }, {
23680           type: "Feature",
23681           properties: {
23682             iso1A2: "CL",
23683             iso1A3: "CHL",
23684             iso1N3: "152",
23685             wikidata: "Q298",
23686             nameEn: "Chile",
23687             groups: ["005", "419", "019", "UN"],
23688             callingCodes: ["56"]
23689           },
23690           geometry: {
23691             type: "MultiPolygon",
23692             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]]]]
23693           }
23694         }, {
23695           type: "Feature",
23696           properties: {
23697             iso1A2: "CM",
23698             iso1A3: "CMR",
23699             iso1N3: "120",
23700             wikidata: "Q1009",
23701             nameEn: "Cameroon",
23702             groups: ["017", "202", "002", "UN"],
23703             callingCodes: ["237"]
23704           },
23705           geometry: {
23706             type: "MultiPolygon",
23707             coordinates: [[[[14.83314, 12.62963], [14.55058, 12.78256], [14.56101, 12.91036], [14.46881, 13.08259], [14.08251, 13.0797], [14.20204, 12.53405], [14.17523, 12.41916], [14.22215, 12.36533], [14.4843, 12.35223], [14.6474, 12.17466], [14.61612, 11.7798], [14.55207, 11.72001], [14.64591, 11.66166], [14.6124, 11.51283], [14.17821, 11.23831], [13.97489, 11.30258], [13.78945, 11.00154], [13.7403, 11.00593], [13.70753, 10.94451], [13.73434, 10.9255], [13.54964, 10.61236], [13.5705, 10.53183], [13.43644, 10.13326], [13.34111, 10.12299], [13.25025, 10.03647], [13.25323, 10.00127], [13.286, 9.9822], [13.27409, 9.93232], [13.24132, 9.91031], [13.25025, 9.86042], [13.29941, 9.8296], [13.25472, 9.76795], [13.22642, 9.57266], [13.02385, 9.49334], [12.85628, 9.36698], [12.91958, 9.33905], [12.90022, 9.11411], [12.81085, 8.91992], [12.79, 8.75361], [12.71701, 8.7595], [12.68722, 8.65938], [12.44146, 8.6152], [12.4489, 8.52536], [12.26123, 8.43696], [12.24782, 8.17904], [12.19271, 8.10826], [12.20909, 7.97553], [11.99908, 7.67302], [12.01844, 7.52981], [11.93205, 7.47812], [11.84864, 7.26098], [11.87396, 7.09398], [11.63117, 6.9905], [11.55818, 6.86186], [11.57755, 6.74059], [11.51499, 6.60892], [11.42264, 6.5882], [11.42041, 6.53789], [11.09495, 6.51717], [11.09644, 6.68437], [10.94302, 6.69325], [10.8179, 6.83377], [10.83727, 6.9358], [10.60789, 7.06885], [10.59746, 7.14719], [10.57214, 7.16345], [10.53639, 6.93432], [10.21466, 6.88996], [10.15135, 7.03781], [9.86314, 6.77756], [9.77824, 6.79088], [9.70674, 6.51717], [9.51757, 6.43874], [8.84209, 5.82562], [8.88156, 5.78857], [8.83687, 5.68483], [8.92029, 5.58403], [8.78027, 5.1243], [8.60302, 4.87353], [8.34397, 4.30689], [9.22018, 3.72052], [9.81162, 2.33797], [9.82123, 2.35097], [9.83754, 2.32428], [9.83238, 2.29079], [9.84716, 2.24676], [9.89012, 2.20457], [9.90749, 2.20049], [9.991, 2.16561], [11.3561, 2.17217], [11.37116, 2.29975], [13.28534, 2.25716], [13.29457, 2.16106], [14.61145, 2.17866], [15.00996, 1.98887], [15.22634, 2.03243], [15.34776, 1.91264], [15.48942, 1.98265], [16.02959, 1.76483], [16.02647, 1.65591], [16.14634, 1.70259], [16.05294, 1.9811], [16.08563, 2.19733], [16.15568, 2.18955], [16.19357, 2.21537], [16.08252, 2.45708], [16.05449, 3.02306], [15.77725, 3.26835], [15.73522, 3.24348], [15.07686, 4.01805], [15.17482, 4.05131], [15.10644, 4.1362], [15.08609, 4.30282], [15.00825, 4.41458], [14.73383, 4.6135], [14.65489, 5.21343], [14.57083, 5.23979], [14.52724, 5.28319], [14.62531, 5.51411], [14.58951, 5.59777], [14.62375, 5.70466], [14.60974, 5.91838], [14.49455, 5.91683], [14.42917, 6.00508], [14.43073, 6.08867], [14.56149, 6.18928], [14.74206, 6.26356], [14.80122, 6.34866], [14.79966, 6.39043], [14.96311, 6.75693], [15.04717, 6.77085], [15.23397, 7.25135], [15.49743, 7.52179], [15.56964, 7.58936], [15.59272, 7.7696], [15.50743, 7.79302], [15.20426, 8.50892], [15.09484, 8.65982], [14.83566, 8.80557], [14.35707, 9.19611], [14.37094, 9.2954], [13.97544, 9.6365], [14.01793, 9.73169], [14.1317, 9.82413], [14.20411, 10.00055], [14.4673, 10.00264], [14.80082, 9.93818], [14.95722, 9.97926], [15.05999, 9.94845], [15.14043, 9.99246], [15.24618, 9.99246], [15.41408, 9.92876], [15.68761, 9.99344], [15.50535, 10.1098], [15.30874, 10.31063], [15.23724, 10.47764], [15.14936, 10.53915], [15.15532, 10.62846], [15.06737, 10.80921], [15.09127, 10.87431], [15.04957, 11.02347], [15.10021, 11.04101], [15.0585, 11.40481], [15.13149, 11.5537], [15.06595, 11.71126], [15.11579, 11.79313], [15.04808, 11.8731], [15.05786, 12.0608], [15.0349, 12.10698], [15.00146, 12.1223], [14.96952, 12.0925], [14.89019, 12.16593], [14.90827, 12.3269], [14.83314, 12.62963]]]]
23708           }
23709         }, {
23710           type: "Feature",
23711           properties: {
23712             iso1A2: "CN",
23713             iso1A3: "CHN",
23714             iso1N3: "156",
23715             wikidata: "Q148",
23716             nameEn: "People's Republic of China"
23717           },
23718           geometry: null
23719         }, {
23720           type: "Feature",
23721           properties: {
23722             iso1A2: "CO",
23723             iso1A3: "COL",
23724             iso1N3: "170",
23725             wikidata: "Q739",
23726             nameEn: "Colombia",
23727             groups: ["005", "419", "019", "UN"],
23728             callingCodes: ["57"]
23729           },
23730           geometry: {
23731             type: "MultiPolygon",
23732             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]]]]
23733           }
23734         }, {
23735           type: "Feature",
23736           properties: {
23737             iso1A2: "CP",
23738             iso1A3: "CPT",
23739             wikidata: "Q161258",
23740             nameEn: "Clipperton Island",
23741             country: "FR",
23742             groups: ["013", "003", "019", "UN"],
23743             isoStatus: "excRes"
23744           },
23745           geometry: {
23746             type: "MultiPolygon",
23747             coordinates: [[[[-110.36279, 9.79626], [-108.755, 9.84085], [-109.04145, 11.13245], [-110.36279, 9.79626]]]]
23748           }
23749         }, {
23750           type: "Feature",
23751           properties: {
23752             iso1A2: "CR",
23753             iso1A3: "CRI",
23754             iso1N3: "188",
23755             wikidata: "Q800",
23756             nameEn: "Costa Rica",
23757             groups: ["013", "003", "419", "019", "UN"],
23758             callingCodes: ["506"]
23759           },
23760           geometry: {
23761             type: "MultiPolygon",
23762             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]]]]
23763           }
23764         }, {
23765           type: "Feature",
23766           properties: {
23767             iso1A2: "CU",
23768             iso1A3: "CUB",
23769             iso1N3: "192",
23770             wikidata: "Q241",
23771             nameEn: "Cuba",
23772             groups: ["029", "003", "419", "019", "UN"],
23773             callingCodes: ["53"]
23774           },
23775           geometry: {
23776             type: "MultiPolygon",
23777             coordinates: [[[[-73.62304, 20.6935], [-82.02215, 24.23074], [-85.77883, 21.92705], [-74.81171, 18.82201], [-73.62304, 20.6935]]]]
23778           }
23779         }, {
23780           type: "Feature",
23781           properties: {
23782             iso1A2: "CV",
23783             iso1A3: "CPV",
23784             iso1N3: "132",
23785             wikidata: "Q1011",
23786             nameEn: "Cape Verde",
23787             groups: ["Q105472", "011", "202", "002", "UN"],
23788             callingCodes: ["238"]
23789           },
23790           geometry: {
23791             type: "MultiPolygon",
23792             coordinates: [[[[-28.81604, 14.57305], [-20.39702, 14.12816], [-23.37101, 19.134], [-28.81604, 14.57305]]]]
23793           }
23794         }, {
23795           type: "Feature",
23796           properties: {
23797             iso1A2: "CW",
23798             iso1A3: "CUW",
23799             iso1N3: "531",
23800             wikidata: "Q25279",
23801             nameEn: "Cura\xE7ao",
23802             aliases: ["NL-CW"],
23803             country: "NL",
23804             groups: ["Q1451600", "029", "003", "419", "019", "UN"],
23805             callingCodes: ["599"]
23806           },
23807           geometry: {
23808             type: "MultiPolygon",
23809             coordinates: [[[[-68.90012, 12.62309], [-69.59009, 12.46019], [-68.99639, 11.79035], [-68.33524, 11.78151], [-68.90012, 12.62309]]]]
23810           }
23811         }, {
23812           type: "Feature",
23813           properties: {
23814             iso1A2: "CX",
23815             iso1A3: "CXR",
23816             iso1N3: "162",
23817             wikidata: "Q31063",
23818             nameEn: "Christmas Island",
23819             country: "AU",
23820             groups: ["053", "009", "UN"],
23821             driveSide: "left",
23822             callingCodes: ["61"]
23823           },
23824           geometry: {
23825             type: "MultiPolygon",
23826             coordinates: [[[[105.66835, -9.31927], [104.67494, -11.2566], [106.66176, -11.14349], [105.66835, -9.31927]]]]
23827           }
23828         }, {
23829           type: "Feature",
23830           properties: {
23831             iso1A2: "CY",
23832             iso1A3: "CYP",
23833             iso1N3: "196",
23834             wikidata: "Q229",
23835             nameEn: "Republic of Cyprus",
23836             groups: ["Q644636", "EU", "145", "142", "UN"],
23837             driveSide: "left",
23838             callingCodes: ["357"]
23839           },
23840           geometry: {
23841             type: "MultiPolygon",
23842             coordinates: [[[[32.46489, 35.48584], [30.15137, 34.08517], [32.74412, 34.43926], [32.75515, 34.64985], [32.76136, 34.68318], [32.79433, 34.67883], [32.82717, 34.70622], [32.86014, 34.70585], [32.86167, 34.68734], [32.9068, 34.66102], [32.91398, 34.67343], [32.93043, 34.67091], [32.92807, 34.66736], [32.93449, 34.66241], [32.93693, 34.67027], [32.94379, 34.67111], [32.94683, 34.67907], [32.95539, 34.68471], [32.99135, 34.68061], [32.98668, 34.67268], [32.99014, 34.65518], [32.97736, 34.65277], [32.97079, 34.66112], [32.95325, 34.66462], [32.94796, 34.6587], [32.94976, 34.65204], [32.95471, 34.64528], [32.95323, 34.64075], [32.95891, 34.62919], [32.96718, 34.63446], [32.96968, 34.64046], [33.0138, 34.64424], [33.26744, 34.49942], [33.83531, 34.73974], [33.70575, 34.97947], [33.70639, 34.99303], [33.71514, 35.00294], [33.69731, 35.01754], [33.69938, 35.03123], [33.67678, 35.03866], [33.63765, 35.03869], [33.61215, 35.0527], [33.59658, 35.03635], [33.567, 35.04803], [33.57478, 35.06049], [33.53975, 35.08151], [33.48915, 35.06594], [33.47666, 35.00701], [33.45256, 35.00288], [33.45178, 35.02078], [33.47825, 35.04103], [33.48136, 35.0636], [33.46813, 35.10564], [33.41675, 35.16325], [33.4076, 35.20062], [33.38575, 35.2018], [33.37248, 35.18698], [33.3717, 35.1788], [33.36569, 35.17479], [33.35612, 35.17402], [33.35596, 35.17942], [33.34964, 35.17803], [33.35056, 35.18328], [33.31955, 35.18096], [33.3072, 35.16816], [33.27068, 35.16815], [33.15138, 35.19504], [33.11105, 35.15639], [33.08249, 35.17319], [33.01192, 35.15639], [32.94471, 35.09422], [32.86406, 35.1043], [32.85733, 35.07742], [32.70779, 35.14127], [32.70947, 35.18328], [32.64864, 35.19967], [32.60361, 35.16647], [32.46489, 35.48584]]], [[[33.74144, 35.01053], [33.7492, 35.01319], [33.74983, 35.02274], [33.74265, 35.02329], [33.73781, 35.02181], [33.7343, 35.01178], [33.74144, 35.01053]]], [[[33.77312, 34.9976], [33.75994, 35.00113], [33.75682, 34.99916], [33.76605, 34.99543], [33.76738, 34.99188], [33.7778, 34.98981], [33.77843, 34.988], [33.78149, 34.98854], [33.78318, 34.98699], [33.78571, 34.98951], [33.78917, 34.98854], [33.79191, 34.98914], [33.78516, 34.99582], [33.77553, 34.99518], [33.77312, 34.9976]]]]
23843           }
23844         }, {
23845           type: "Feature",
23846           properties: {
23847             iso1A2: "CZ",
23848             iso1A3: "CZE",
23849             iso1N3: "203",
23850             wikidata: "Q213",
23851             nameEn: "Czechia",
23852             groups: ["EU", "151", "150", "UN"],
23853             callingCodes: ["420"]
23854           },
23855           geometry: {
23856             type: "MultiPolygon",
23857             coordinates: [[[[14.82803, 50.86966], [14.79139, 50.81438], [14.70661, 50.84096], [14.61993, 50.86049], [14.63434, 50.8883], [14.65259, 50.90513], [14.64802, 50.93241], [14.58024, 50.91443], [14.56374, 50.922], [14.59702, 50.96148], [14.59908, 50.98685], [14.58215, 50.99306], [14.56432, 51.01008], [14.53438, 51.00374], [14.53321, 51.01679], [14.49873, 51.02242], [14.50809, 51.0427], [14.49991, 51.04692], [14.49154, 51.04382], [14.49202, 51.02286], [14.45827, 51.03712], [14.41335, 51.02086], [14.30098, 51.05515], [14.25665, 50.98935], [14.28776, 50.97718], [14.32353, 50.98556], [14.32793, 50.97379], [14.30251, 50.96606], [14.31422, 50.95243], [14.39848, 50.93866], [14.38691, 50.89907], [14.30098, 50.88448], [14.27123, 50.89386], [14.24314, 50.88761], [14.22331, 50.86049], [14.02982, 50.80662], [13.98864, 50.8177], [13.89113, 50.78533], [13.89444, 50.74142], [13.82942, 50.7251], [13.76316, 50.73487], [13.70204, 50.71771], [13.65977, 50.73096], [13.52474, 50.70394], [13.53748, 50.67654], [13.5226, 50.64721], [13.49742, 50.63133], [13.46413, 50.60102], [13.42189, 50.61243], [13.37485, 50.64931], [13.37805, 50.627], [13.32264, 50.60317], [13.32594, 50.58009], [13.29454, 50.57904], [13.25158, 50.59268], [13.19043, 50.50237], [13.13424, 50.51709], [13.08301, 50.50132], [13.0312, 50.50944], [13.02038, 50.4734], [13.02147, 50.44763], [12.98433, 50.42016], [12.94058, 50.40944], [12.82465, 50.45738], [12.73476, 50.43237], [12.73044, 50.42268], [12.70731, 50.39948], [12.67261, 50.41949], [12.51356, 50.39694], [12.48747, 50.37278], [12.49214, 50.35228], [12.48256, 50.34784], [12.46643, 50.35527], [12.43722, 50.33774], [12.43371, 50.32506], [12.39924, 50.32302], [12.40158, 50.29521], [12.36594, 50.28289], [12.35425, 50.23993], [12.33263, 50.24367], [12.32445, 50.20442], [12.33847, 50.19432], [12.32596, 50.17146], [12.29232, 50.17524], [12.28063, 50.19544], [12.28755, 50.22429], [12.23943, 50.24594], [12.24791, 50.25525], [12.26953, 50.25189], [12.25119, 50.27079], [12.20823, 50.2729], [12.18013, 50.32146], [12.10907, 50.32041], [12.13716, 50.27396], [12.09287, 50.25032], [12.19335, 50.19997], [12.21484, 50.16399], [12.1917, 50.13434], [12.2073, 50.10315], [12.23709, 50.10213], [12.27433, 50.0771], [12.26111, 50.06331], [12.30798, 50.05719], [12.49908, 49.97305], [12.47264, 49.94222], [12.55197, 49.92094], [12.48256, 49.83575], [12.46603, 49.78882], [12.40489, 49.76321], [12.4462, 49.70233], [12.52553, 49.68415], [12.53544, 49.61888], [12.56188, 49.6146], [12.60155, 49.52887], [12.64782, 49.52565], [12.64121, 49.47628], [12.669, 49.42935], [12.71227, 49.42363], [12.75854, 49.3989], [12.78168, 49.34618], [12.88414, 49.33541], [12.88249, 49.35479], [12.94859, 49.34079], [13.03618, 49.30417], [13.02957, 49.27399], [13.05883, 49.26259], [13.17665, 49.16713], [13.17019, 49.14339], [13.20405, 49.12303], [13.23689, 49.11412], [13.28242, 49.1228], [13.39479, 49.04812], [13.40802, 48.98851], [13.50221, 48.93752], [13.50552, 48.97441], [13.58319, 48.96899], [13.61624, 48.9462], [13.67739, 48.87886], [13.73854, 48.88538], [13.76994, 48.83537], [13.78977, 48.83319], [13.8096, 48.77877], [13.84023, 48.76988], [14.06151, 48.66873], [14.01482, 48.63788], [14.09104, 48.5943], [14.20691, 48.5898], [14.33909, 48.55852], [14.43076, 48.58855], [14.4587, 48.64695], [14.56139, 48.60429], [14.60808, 48.62881], [14.66762, 48.58215], [14.71794, 48.59794], [14.72756, 48.69502], [14.80584, 48.73489], [14.80821, 48.77711], [14.81545, 48.7874], [14.94773, 48.76268], [14.95641, 48.75915], [14.9758, 48.76857], [14.98112, 48.77524], [14.9782, 48.7766], [14.98032, 48.77959], [14.95072, 48.79101], [14.98917, 48.90082], [14.97612, 48.96983], [14.99878, 49.01444], [15.15534, 48.99056], [15.16358, 48.94278], [15.26177, 48.95766], [15.28305, 48.98831], [15.34823, 48.98444], [15.48027, 48.94481], [15.51357, 48.91549], [15.61622, 48.89541], [15.6921, 48.85973], [15.75341, 48.8516], [15.78087, 48.87644], [15.84404, 48.86921], [16.06034, 48.75436], [16.37345, 48.729], [16.40915, 48.74576], [16.46134, 48.80865], [16.67008, 48.77699], [16.68518, 48.7281], [16.71883, 48.73806], [16.79779, 48.70998], [16.90354, 48.71541], [16.93955, 48.60371], [17.00215, 48.70887], [17.11202, 48.82925], [17.19355, 48.87602], [17.29054, 48.85546], [17.3853, 48.80936], [17.45671, 48.85004], [17.5295, 48.81117], [17.7094, 48.86721], [17.73126, 48.87885], [17.77944, 48.92318], [17.87831, 48.92679], [17.91814, 49.01784], [18.06885, 49.03157], [18.1104, 49.08624], [18.15022, 49.24518], [18.18456, 49.28909], [18.36446, 49.3267], [18.4139, 49.36517], [18.4084, 49.40003], [18.44686, 49.39467], [18.54848, 49.47059], [18.53063, 49.49022], [18.57183, 49.51162], [18.6144, 49.49824], [18.67757, 49.50895], [18.74761, 49.492], [18.84521, 49.51672], [18.84786, 49.5446], [18.80479, 49.6815], [18.72838, 49.68163], [18.69817, 49.70473], [18.62676, 49.71983], [18.62943, 49.74603], [18.62645, 49.75002], [18.61368, 49.75426], [18.61278, 49.7618], [18.57183, 49.83334], [18.60341, 49.86256], [18.57045, 49.87849], [18.57697, 49.91565], [18.54299, 49.92537], [18.54495, 49.9079], [18.53423, 49.89906], [18.41604, 49.93498], [18.33562, 49.94747], [18.33278, 49.92415], [18.31914, 49.91565], [18.27794, 49.93863], [18.27107, 49.96779], [18.21752, 49.97309], [18.20241, 49.99958], [18.10628, 50.00223], [18.07898, 50.04535], [18.03212, 50.06574], [18.00396, 50.04954], [18.04585, 50.03311], [18.04585, 50.01194], [18.00191, 50.01723], [17.86886, 49.97452], [17.77669, 50.02253], [17.7506, 50.07896], [17.6888, 50.12037], [17.66683, 50.10275], [17.59404, 50.16437], [17.70528, 50.18812], [17.76296, 50.23382], [17.72176, 50.25665], [17.74648, 50.29966], [17.69292, 50.32859], [17.67764, 50.28977], [17.58889, 50.27837], [17.3702, 50.28123], [17.34548, 50.2628], [17.34273, 50.32947], [17.27681, 50.32246], [17.19991, 50.3654], [17.19579, 50.38817], [17.14498, 50.38117], [17.1224, 50.39494], [16.89229, 50.45117], [16.85933, 50.41093], [16.90877, 50.38642], [16.94448, 50.31281], [16.99803, 50.30316], [17.02138, 50.27772], [16.99803, 50.25753], [17.02825, 50.23118], [17.00353, 50.21449], [16.98018, 50.24172], [16.8456, 50.20834], [16.7014, 50.09659], [16.63137, 50.1142], [16.55446, 50.16613], [16.56407, 50.21009], [16.42674, 50.32509], [16.39379, 50.3207], [16.3622, 50.34875], [16.36495, 50.37679], [16.30289, 50.38292], [16.28118, 50.36891], [16.22821, 50.41054], [16.21585, 50.40627], [16.19526, 50.43291], [16.31413, 50.50274], [16.34572, 50.49575], [16.44597, 50.58041], [16.33611, 50.66579], [16.23174, 50.67101], [16.20839, 50.63096], [16.10265, 50.66405], [16.02437, 50.60046], [15.98317, 50.61528], [16.0175, 50.63009], [15.97219, 50.69799], [15.87331, 50.67188], [15.81683, 50.75666], [15.73186, 50.73885], [15.43798, 50.80833], [15.3803, 50.77187], [15.36656, 50.83956], [15.2773, 50.8907], [15.27043, 50.97724], [15.2361, 50.99886], [15.1743, 50.9833], [15.16744, 51.01959], [15.11937, 50.99021], [15.10152, 51.01095], [15.06218, 51.02269], [15.03895, 51.0123], [15.02433, 51.0242], [14.96419, 50.99108], [15.01088, 50.97984], [14.99852, 50.86817], [14.82803, 50.86966]]]]
23858           }
23859         }, {
23860           type: "Feature",
23861           properties: {
23862             iso1A2: "DE",
23863             iso1A3: "DEU",
23864             iso1N3: "276",
23865             wikidata: "Q183",
23866             nameEn: "Germany",
23867             groups: ["EU", "155", "150", "UN"],
23868             callingCodes: ["49"]
23869           },
23870           geometry: {
23871             type: "MultiPolygon",
23872             coordinates: [[[[8.70847, 47.68904], [8.71773, 47.69088], [8.70237, 47.71453], [8.66416, 47.71367], [8.67508, 47.6979], [8.65769, 47.68928], [8.66837, 47.68437], [8.68985, 47.69552], [8.70847, 47.68904]]], [[[8.72617, 47.69651], [8.72809, 47.69282], [8.75856, 47.68969], [8.79511, 47.67462], [8.79966, 47.70222], [8.76965, 47.7075], [8.77309, 47.72059], [8.80663, 47.73821], [8.82002, 47.71458], [8.86989, 47.70504], [8.85065, 47.68209], [8.87383, 47.67045], [8.87625, 47.65441], [8.89946, 47.64769], [8.94093, 47.65596], [9.02093, 47.6868], [9.09891, 47.67801], [9.13845, 47.66389], [9.15181, 47.66904], [9.1705, 47.65513], [9.1755, 47.65584], [9.17593, 47.65399], [9.18203, 47.65598], [9.25619, 47.65939], [9.55125, 47.53629], [9.72736, 47.53457], [9.76748, 47.5934], [9.80254, 47.59419], [9.82591, 47.58158], [9.8189, 47.54688], [9.87499, 47.52953], [9.87733, 47.54688], [9.92407, 47.53111], [9.96029, 47.53899], [10.00003, 47.48216], [10.03859, 47.48927], [10.07131, 47.45531], [10.09001, 47.46005], [10.1052, 47.4316], [10.06897, 47.40709], [10.09819, 47.35724], [10.11805, 47.37228], [10.16362, 47.36674], [10.17648, 47.38889], [10.2127, 47.38019], [10.22774, 47.38904], [10.23757, 47.37609], [10.19998, 47.32832], [10.2147, 47.31014], [10.17648, 47.29149], [10.17531, 47.27167], [10.23257, 47.27088], [10.33424, 47.30813], [10.39851, 47.37623], [10.4324, 47.38494], [10.4359, 47.41183], [10.47446, 47.43318], [10.46278, 47.47901], [10.44291, 47.48453], [10.4324, 47.50111], [10.44992, 47.5524], [10.43473, 47.58394], [10.47329, 47.58552], [10.48849, 47.54057], [10.56912, 47.53584], [10.60337, 47.56755], [10.63456, 47.5591], [10.68832, 47.55752], [10.6965, 47.54253], [10.7596, 47.53228], [10.77596, 47.51729], [10.88814, 47.53701], [10.91268, 47.51334], [10.86945, 47.5015], [10.87061, 47.4786], [10.90918, 47.48571], [10.93839, 47.48018], [10.92437, 47.46991], [10.98513, 47.42882], [10.97111, 47.41617], [10.97111, 47.39561], [11.11835, 47.39719], [11.12536, 47.41222], [11.20482, 47.43198], [11.25157, 47.43277], [11.22002, 47.3964], [11.27844, 47.39956], [11.29597, 47.42566], [11.33804, 47.44937], [11.4175, 47.44621], [11.38128, 47.47465], [11.4362, 47.51413], [11.52618, 47.50939], [11.58578, 47.52281], [11.58811, 47.55515], [11.60681, 47.57881], [11.63934, 47.59202], [11.84052, 47.58354], [11.85572, 47.60166], [12.0088, 47.62451], [12.02282, 47.61033], [12.05788, 47.61742], [12.13734, 47.60639], [12.17824, 47.61506], [12.18145, 47.61019], [12.17737, 47.60121], [12.18568, 47.6049], [12.20398, 47.60667], [12.20801, 47.61082], [12.19895, 47.64085], [12.18507, 47.65984], [12.18347, 47.66663], [12.16769, 47.68167], [12.16217, 47.70105], [12.18303, 47.70065], [12.22571, 47.71776], [12.2542, 47.7433], [12.26238, 47.73544], [12.24017, 47.69534], [12.26004, 47.67725], [12.27991, 47.68827], [12.336, 47.69534], [12.37222, 47.68433], [12.43883, 47.6977], [12.44117, 47.6741], [12.50076, 47.62293], [12.53816, 47.63553], [12.57438, 47.63238], [12.6071, 47.6741], [12.7357, 47.6787], [12.77777, 47.66689], [12.76492, 47.64485], [12.82101, 47.61493], [12.77427, 47.58025], [12.80699, 47.54477], [12.84672, 47.54556], [12.85256, 47.52741], [12.9624, 47.47452], [12.98344, 47.48716], [12.9998, 47.46267], [13.04537, 47.49426], [13.03252, 47.53373], [13.05355, 47.56291], [13.04537, 47.58183], [13.06641, 47.58577], [13.06407, 47.60075], [13.09562, 47.63304], [13.07692, 47.68814], [13.01382, 47.72116], [12.98578, 47.7078], [12.92969, 47.71094], [12.91333, 47.7178], [12.90274, 47.72513], [12.91711, 47.74026], [12.9353, 47.74788], [12.94371, 47.76281], [12.93202, 47.77302], [12.96311, 47.79957], [12.98543, 47.82896], [13.00588, 47.84374], [12.94163, 47.92927], [12.93886, 47.94046], [12.93642, 47.94436], [12.93419, 47.94063], [12.92668, 47.93879], [12.91985, 47.94069], [12.9211, 47.95135], [12.91683, 47.95647], [12.87476, 47.96195], [12.8549, 48.01122], [12.76141, 48.07373], [12.74973, 48.10885], [12.7617, 48.12796], [12.78595, 48.12445], [12.80676, 48.14979], [12.82673, 48.15245], [12.8362, 48.15876], [12.836, 48.1647], [12.84475, 48.16556], [12.87126, 48.20318], [12.95306, 48.20629], [13.02083, 48.25689], [13.0851, 48.27711], [13.126, 48.27867], [13.18093, 48.29577], [13.26039, 48.29422], [13.30897, 48.31575], [13.40709, 48.37292], [13.43929, 48.43386], [13.42527, 48.45711], [13.45727, 48.51092], [13.43695, 48.55776], [13.45214, 48.56472], [13.46967, 48.55157], [13.50663, 48.57506], [13.50131, 48.58091], [13.51291, 48.59023], [13.57535, 48.55912], [13.59705, 48.57013], [13.62508, 48.55501], [13.65186, 48.55092], [13.66113, 48.53558], [13.72802, 48.51208], [13.74816, 48.53058], [13.7513, 48.5624], [13.76921, 48.55324], [13.80519, 48.58026], [13.80038, 48.59487], [13.82609, 48.62345], [13.81901, 48.6761], [13.81283, 48.68426], [13.81791, 48.69832], [13.79337, 48.71375], [13.81863, 48.73257], [13.82266, 48.75544], [13.84023, 48.76988], [13.8096, 48.77877], [13.78977, 48.83319], [13.76994, 48.83537], [13.73854, 48.88538], [13.67739, 48.87886], [13.61624, 48.9462], [13.58319, 48.96899], [13.50552, 48.97441], [13.50221, 48.93752], [13.40802, 48.98851], [13.39479, 49.04812], [13.28242, 49.1228], [13.23689, 49.11412], [13.20405, 49.12303], [13.17019, 49.14339], [13.17665, 49.16713], [13.05883, 49.26259], [13.02957, 49.27399], [13.03618, 49.30417], [12.94859, 49.34079], [12.88249, 49.35479], [12.88414, 49.33541], [12.78168, 49.34618], [12.75854, 49.3989], [12.71227, 49.42363], [12.669, 49.42935], [12.64121, 49.47628], [12.64782, 49.52565], [12.60155, 49.52887], [12.56188, 49.6146], [12.53544, 49.61888], [12.52553, 49.68415], [12.4462, 49.70233], [12.40489, 49.76321], [12.46603, 49.78882], [12.48256, 49.83575], [12.55197, 49.92094], [12.47264, 49.94222], [12.49908, 49.97305], [12.30798, 50.05719], [12.26111, 50.06331], [12.27433, 50.0771], [12.23709, 50.10213], [12.2073, 50.10315], [12.1917, 50.13434], [12.21484, 50.16399], [12.19335, 50.19997], [12.09287, 50.25032], [12.13716, 50.27396], [12.10907, 50.32041], [12.18013, 50.32146], [12.20823, 50.2729], [12.25119, 50.27079], [12.26953, 50.25189], [12.24791, 50.25525], [12.23943, 50.24594], [12.28755, 50.22429], [12.28063, 50.19544], [12.29232, 50.17524], [12.32596, 50.17146], [12.33847, 50.19432], [12.32445, 50.20442], [12.33263, 50.24367], [12.35425, 50.23993], [12.36594, 50.28289], [12.40158, 50.29521], [12.39924, 50.32302], [12.43371, 50.32506], [12.43722, 50.33774], [12.46643, 50.35527], [12.48256, 50.34784], [12.49214, 50.35228], [12.48747, 50.37278], [12.51356, 50.39694], [12.67261, 50.41949], [12.70731, 50.39948], [12.73044, 50.42268], [12.73476, 50.43237], [12.82465, 50.45738], [12.94058, 50.40944], [12.98433, 50.42016], [13.02147, 50.44763], [13.02038, 50.4734], [13.0312, 50.50944], [13.08301, 50.50132], [13.13424, 50.51709], [13.19043, 50.50237], [13.25158, 50.59268], [13.29454, 50.57904], [13.32594, 50.58009], [13.32264, 50.60317], [13.37805, 50.627], [13.37485, 50.64931], [13.42189, 50.61243], [13.46413, 50.60102], [13.49742, 50.63133], [13.5226, 50.64721], [13.53748, 50.67654], [13.52474, 50.70394], [13.65977, 50.73096], [13.70204, 50.71771], [13.76316, 50.73487], [13.82942, 50.7251], [13.89444, 50.74142], [13.89113, 50.78533], [13.98864, 50.8177], [14.02982, 50.80662], [14.22331, 50.86049], [14.24314, 50.88761], [14.27123, 50.89386], [14.30098, 50.88448], [14.38691, 50.89907], [14.39848, 50.93866], [14.31422, 50.95243], [14.30251, 50.96606], [14.32793, 50.97379], [14.32353, 50.98556], [14.28776, 50.97718], [14.25665, 50.98935], [14.30098, 51.05515], [14.41335, 51.02086], [14.45827, 51.03712], [14.49202, 51.02286], [14.49154, 51.04382], [14.49991, 51.04692], [14.50809, 51.0427], [14.49873, 51.02242], [14.53321, 51.01679], [14.53438, 51.00374], [14.56432, 51.01008], [14.58215, 50.99306], [14.59908, 50.98685], [14.59702, 50.96148], [14.56374, 50.922], [14.58024, 50.91443], [14.64802, 50.93241], [14.65259, 50.90513], [14.63434, 50.8883], [14.61993, 50.86049], [14.70661, 50.84096], [14.79139, 50.81438], [14.82803, 50.86966], [14.81664, 50.88148], [14.89681, 50.9422], [14.89252, 50.94999], [14.92942, 50.99744], [14.95529, 51.04552], [14.97938, 51.07742], [14.98229, 51.11354], [14.99689, 51.12205], [14.99079, 51.14284], [14.99646, 51.14365], [15.00083, 51.14974], [14.99414, 51.15813], [14.99311, 51.16249], [15.0047, 51.16874], [15.01242, 51.21285], [15.04288, 51.28387], [14.98008, 51.33449], [14.96899, 51.38367], [14.9652, 51.44793], [14.94749, 51.47155], [14.73219, 51.52922], [14.72652, 51.53902], [14.73047, 51.54606], [14.71125, 51.56209], [14.7727, 51.61263], [14.75759, 51.62318], [14.75392, 51.67445], [14.69065, 51.70842], [14.66386, 51.73282], [14.64625, 51.79472], [14.60493, 51.80473], [14.59089, 51.83302], [14.6588, 51.88359], [14.6933, 51.9044], [14.70601, 51.92944], [14.7177, 51.94048], [14.72163, 51.95188], [14.71836, 51.95606], [14.7139, 51.95643], [14.70488, 51.97679], [14.71339, 52.00337], [14.76026, 52.06624], [14.72971, 52.09167], [14.6917, 52.10283], [14.67683, 52.13936], [14.70616, 52.16927], [14.68344, 52.19612], [14.71319, 52.22144], [14.70139, 52.25038], [14.58149, 52.28007], [14.56378, 52.33838], [14.55228, 52.35264], [14.54423, 52.42568], [14.63056, 52.48993], [14.60081, 52.53116], [14.6289, 52.57136], [14.61073, 52.59847], [14.22071, 52.81175], [14.13806, 52.82392], [14.12256, 52.84311], [14.15873, 52.87715], [14.14056, 52.95786], [14.25954, 53.00264], [14.35044, 53.05829], [14.38679, 53.13669], [14.36696, 53.16444], [14.37853, 53.20405], [14.40662, 53.21098], [14.45125, 53.26241], [14.44133, 53.27427], [14.4215, 53.27724], [14.35209, 53.49506], [14.3273, 53.50587], [14.30416, 53.55499], [14.31904, 53.61581], [14.2853, 53.63392], [14.28477, 53.65955], [14.27133, 53.66613], [14.2836, 53.67721], [14.26782, 53.69866], [14.27249, 53.74464], [14.21323, 53.8664], [14.20823, 53.90776], [14.18544, 53.91258], [14.20647, 53.91671], [14.22634, 53.9291], [14.20811, 54.12784], [13.93395, 54.84044], [12.85844, 54.82438], [11.90309, 54.38543], [11.00303, 54.63689], [10.31111, 54.65968], [10.16755, 54.73883], [9.89314, 54.84171], [9.73563, 54.8247], [9.61187, 54.85548], [9.62734, 54.88057], [9.58937, 54.88785], [9.4659, 54.83131], [9.43155, 54.82586], [9.41213, 54.84254], [9.38532, 54.83968], [9.36496, 54.81749], [9.33849, 54.80233], [9.32771, 54.80602], [9.2474, 54.8112], [9.23445, 54.83432], [9.24631, 54.84726], [9.20571, 54.85841], [9.14275, 54.87421], [9.04629, 54.87249], [8.92795, 54.90452], [8.81178, 54.90518], [8.76387, 54.8948], [8.63979, 54.91069], [8.55769, 54.91837], [8.45719, 55.06747], [8.02459, 55.09613], [5.45168, 54.20039], [6.91025, 53.44221], [7.00198, 53.32672], [7.19052, 53.31866], [7.21679, 53.20058], [7.22681, 53.18165], [7.17898, 53.13817], [7.21694, 53.00742], [7.07253, 52.81083], [7.04557, 52.63318], [6.77307, 52.65375], [6.71641, 52.62905], [6.69507, 52.488], [6.94293, 52.43597], [6.99041, 52.47235], [7.03417, 52.40237], [7.07044, 52.37805], [7.02703, 52.27941], [7.06365, 52.23789], [7.03729, 52.22695], [6.9897, 52.2271], [6.97189, 52.20329], [6.83984, 52.11728], [6.76117, 52.11895], [6.68128, 52.05052], [6.83035, 51.9905], [6.82357, 51.96711], [6.72319, 51.89518], [6.68386, 51.91861], [6.58556, 51.89386], [6.50231, 51.86313], [6.47179, 51.85395], [6.38815, 51.87257], [6.40704, 51.82771], [6.30593, 51.84998], [6.29872, 51.86801], [6.21443, 51.86801], [6.15349, 51.90439], [6.11551, 51.89769], [6.16902, 51.84094], [6.10337, 51.84829], [6.06705, 51.86136], [5.99848, 51.83195], [5.94568, 51.82786], [5.98665, 51.76944], [5.95003, 51.7493], [6.04091, 51.71821], [6.02767, 51.6742], [6.11759, 51.65609], [6.09055, 51.60564], [6.18017, 51.54096], [6.21724, 51.48568], [6.20654, 51.40049], [6.22641, 51.39948], [6.22674, 51.36135], [6.16977, 51.33169], [6.07889, 51.24432], [6.07889, 51.17038], [6.17384, 51.19589], [6.16706, 51.15677], [5.98292, 51.07469], [5.9541, 51.03496], [5.9134, 51.06736], [5.86735, 51.05182], [5.87849, 51.01969], [5.90493, 51.00198], [5.90296, 50.97356], [5.95282, 50.98728], [6.02697, 50.98303], [6.01615, 50.93367], [6.09297, 50.92066], [6.07486, 50.89307], [6.08805, 50.87223], [6.07693, 50.86025], [6.07431, 50.84674], [6.05702, 50.85179], [6.05623, 50.8572], [6.01921, 50.84435], [6.02328, 50.81694], [6.00462, 50.80065], [5.98404, 50.80988], [5.97497, 50.79992], [6.02624, 50.77453], [6.01976, 50.75398], [6.03889, 50.74618], [6.0326, 50.72647], [6.0406, 50.71848], [6.04428, 50.72861], [6.11707, 50.72231], [6.17852, 50.6245], [6.26957, 50.62444], [6.2476, 50.60392], [6.24888, 50.59869], [6.24005, 50.58732], [6.22581, 50.5907], [6.20281, 50.56952], [6.17739, 50.55875], [6.17802, 50.54179], [6.19735, 50.53576], [6.19579, 50.5313], [6.18716, 50.52653], [6.19193, 50.5212], [6.20599, 50.52089], [6.22335, 50.49578], [6.26637, 50.50272], [6.30809, 50.50058], [6.3465, 50.48833], [6.34005, 50.46083], [6.37219, 50.45397], [6.36852, 50.40776], [6.34406, 50.37994], [6.3688, 50.35898], [6.40785, 50.33557], [6.40641, 50.32425], [6.35701, 50.31139], [6.32488, 50.32333], [6.29949, 50.30887], [6.28797, 50.27458], [6.208, 50.25179], [6.16853, 50.2234], [6.18364, 50.20815], [6.18739, 50.1822], [6.14588, 50.17106], [6.14132, 50.14971], [6.15298, 50.14126], [6.1379, 50.12964], [6.12055, 50.09171], [6.11274, 50.05916], [6.13458, 50.04141], [6.13044, 50.02929], [6.14666, 50.02207], [6.13794, 50.01466], [6.13273, 50.02019], [6.1295, 50.01849], [6.13806, 50.01056], [6.14948, 50.00908], [6.14147, 49.99563], [6.1701, 49.98518], [6.16466, 49.97086], [6.17872, 49.9537], [6.18554, 49.95622], [6.18045, 49.96611], [6.19089, 49.96991], [6.19856, 49.95053], [6.22094, 49.94955], [6.22608, 49.929], [6.21882, 49.92403], [6.22926, 49.92096], [6.23496, 49.89972], [6.26146, 49.88203], [6.28874, 49.87592], [6.29692, 49.86685], [6.30963, 49.87021], [6.32303, 49.85133], [6.32098, 49.83728], [6.33585, 49.83785], [6.34267, 49.84974], [6.36576, 49.85032], [6.40022, 49.82029], [6.42521, 49.81591], [6.42905, 49.81091], [6.44131, 49.81443], [6.45425, 49.81164], [6.47111, 49.82263], [6.48718, 49.81267], [6.50647, 49.80916], [6.51215, 49.80124], [6.52121, 49.81338], [6.53122, 49.80666], [6.52169, 49.79787], [6.50534, 49.78952], [6.51669, 49.78336], [6.51056, 49.77515], [6.51828, 49.76855], [6.51646, 49.75961], [6.50174, 49.75292], [6.50193, 49.73291], [6.51805, 49.72425], [6.51397, 49.72058], [6.50261, 49.72718], [6.49535, 49.72645], [6.49694, 49.72205], [6.5042, 49.71808], [6.50647, 49.71353], [6.49785, 49.71118], [6.48014, 49.69767], [6.46048, 49.69092], [6.44654, 49.67799], [6.42937, 49.66857], [6.42726, 49.66078], [6.43768, 49.66021], [6.4413, 49.65722], [6.41861, 49.61723], [6.39822, 49.60081], [6.385, 49.59946], [6.37464, 49.58886], [6.38342, 49.5799], [6.38024, 49.57593], [6.36676, 49.57813], [6.35825, 49.57053], [6.38228, 49.55855], [6.38072, 49.55171], [6.35666, 49.52931], [6.36788, 49.50377], [6.36907, 49.48931], [6.36778, 49.46937], [6.38352, 49.46463], [6.39168, 49.4667], [6.40274, 49.46546], [6.42432, 49.47683], [6.55404, 49.42464], [6.533, 49.40748], [6.60091, 49.36864], [6.58807, 49.35358], [6.572, 49.35027], [6.60186, 49.31055], [6.66583, 49.28065], [6.69274, 49.21661], [6.71843, 49.2208], [6.73256, 49.20486], [6.71137, 49.18808], [6.73765, 49.16375], [6.78265, 49.16793], [6.83385, 49.15162], [6.84703, 49.15734], [6.86225, 49.18185], [6.85016, 49.19354], [6.85119, 49.20038], [6.83555, 49.21249], [6.85939, 49.22376], [6.89298, 49.20863], [6.91875, 49.22261], [6.93831, 49.2223], [6.94028, 49.21641], [6.95963, 49.203], [6.97273, 49.2099], [7.01318, 49.19018], [7.03459, 49.19096], [7.0274, 49.17042], [7.03178, 49.15734], [7.04662, 49.13724], [7.04409, 49.12123], [7.04843, 49.11422], [7.05548, 49.11185], [7.06642, 49.11415], [7.07162, 49.1255], [7.09007, 49.13094], [7.07859, 49.15031], [7.10715, 49.15631], [7.10384, 49.13787], [7.12504, 49.14253], [7.1358, 49.1282], [7.1593, 49.1204], [7.23473, 49.12971], [7.29514, 49.11426], [7.3195, 49.14231], [7.35995, 49.14399], [7.3662, 49.17308], [7.44052, 49.18354], [7.44455, 49.16765], [7.49473, 49.17], [7.49172, 49.13915], [7.53012, 49.09818], [7.56416, 49.08136], [7.62575, 49.07654], [7.63618, 49.05428], [7.75948, 49.04562], [7.79557, 49.06583], [7.86386, 49.03499], [7.93641, 49.05544], [7.97783, 49.03161], [8.14189, 48.97833], [8.22604, 48.97352], [8.20031, 48.95856], [8.19989, 48.95825], [8.12813, 48.87985], [8.10253, 48.81829], [8.06802, 48.78957], [8.0326, 48.79017], [8.01534, 48.76085], [7.96994, 48.75606], [7.96812, 48.72491], [7.89002, 48.66317], [7.84098, 48.64217], [7.80057, 48.5857], [7.80167, 48.54758], [7.80647, 48.51239], [7.76833, 48.48945], [7.73109, 48.39192], [7.74562, 48.32736], [7.69022, 48.30018], [7.6648, 48.22219], [7.57137, 48.12292], [7.56966, 48.03265], [7.62302, 47.97898], [7.55673, 47.87371], [7.52921, 47.77747], [7.54761, 47.72912], [7.53722, 47.71635], [7.51266, 47.70197], [7.51915, 47.68335], [7.52067, 47.66437], [7.53384, 47.65115], [7.5591, 47.63849], [7.57423, 47.61628], [7.58851, 47.60794], [7.59301, 47.60058], [7.58945, 47.59017], [7.60523, 47.58519], [7.60459, 47.57869], [7.61929, 47.57683], [7.64309, 47.59151], [7.64213, 47.5944], [7.64599, 47.59695], [7.67395, 47.59212], [7.68229, 47.59905], [7.69385, 47.60099], [7.68486, 47.59601], [7.67115, 47.5871], [7.68904, 47.57133], [7.67655, 47.56435], [7.63338, 47.56256], [7.65083, 47.54662], [7.66174, 47.54554], [7.6656, 47.53752], [7.68101, 47.53232], [7.69642, 47.53297], [7.71961, 47.54219], [7.75261, 47.54599], [7.79486, 47.55691], [7.81901, 47.58798], [7.84412, 47.5841], [7.88664, 47.58854], [7.90673, 47.57674], [7.91251, 47.55031], [7.94494, 47.54511], [7.95682, 47.55789], [7.97581, 47.55493], [8.00113, 47.55616], [8.02136, 47.55096], [8.04383, 47.55443], [8.06663, 47.56374], [8.08557, 47.55768], [8.10002, 47.56504], [8.10395, 47.57918], [8.11543, 47.5841], [8.13662, 47.58432], [8.13823, 47.59147], [8.14947, 47.59558], [8.1652, 47.5945], [8.19378, 47.61636], [8.20617, 47.62141], [8.22011, 47.6181], [8.22577, 47.60385], [8.23809, 47.61204], [8.25863, 47.61571], [8.26313, 47.6103], [8.2824, 47.61225], [8.29722, 47.60603], [8.29524, 47.5919], [8.30277, 47.58607], [8.32735, 47.57133], [8.35512, 47.57014], [8.38273, 47.56608], [8.39477, 47.57826], [8.43235, 47.56617], [8.49431, 47.58107], [8.48949, 47.588], [8.46637, 47.58389], [8.45578, 47.60121], [8.50747, 47.61897], [8.51686, 47.63476], [8.55756, 47.62394], [8.57586, 47.59537], [8.60348, 47.61204], [8.59545, 47.64298], [8.60701, 47.65271], [8.61471, 47.64514], [8.60412, 47.63735], [8.62049, 47.63757], [8.62884, 47.65098], [8.61113, 47.66332], [8.6052, 47.67258], [8.57683, 47.66158], [8.56141, 47.67088], [8.52801, 47.66059], [8.5322, 47.64687], [8.49656, 47.64709], [8.46605, 47.64103], [8.4667, 47.65747], [8.44711, 47.65379], [8.42264, 47.66667], [8.41346, 47.66676], [8.40473, 47.67499], [8.4211, 47.68407], [8.40569, 47.69855], [8.44807, 47.72426], [8.45771, 47.7493], [8.48868, 47.77215], [8.56814, 47.78001], [8.56415, 47.80633], [8.61657, 47.79998], [8.62408, 47.7626], [8.64425, 47.76398], [8.65292, 47.80066], [8.68022, 47.78599], [8.68985, 47.75686], [8.71778, 47.76571], [8.74251, 47.75168], [8.70543, 47.73121], [8.73671, 47.7169], [8.72617, 47.69651]]]]
23873           }
23874         }, {
23875           type: "Feature",
23876           properties: {
23877             iso1A2: "DG",
23878             iso1A3: "DGA",
23879             wikidata: "Q184851",
23880             nameEn: "Diego Garcia",
23881             country: "GB",
23882             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
23883             isoStatus: "excRes",
23884             callingCodes: ["246"]
23885           },
23886           geometry: {
23887             type: "MultiPolygon",
23888             coordinates: [[[[73.14823, -7.76302], [73.09982, -6.07324], [71.43792, -7.73904], [73.14823, -7.76302]]]]
23889           }
23890         }, {
23891           type: "Feature",
23892           properties: {
23893             iso1A2: "DJ",
23894             iso1A3: "DJI",
23895             iso1N3: "262",
23896             wikidata: "Q977",
23897             nameEn: "Djibouti",
23898             groups: ["014", "202", "002", "UN"],
23899             callingCodes: ["253"]
23900           },
23901           geometry: {
23902             type: "MultiPolygon",
23903             coordinates: [[[[43.90659, 12.3823], [43.90659, 12.3823], [43.32909, 12.59711], [43.29075, 12.79154], [42.86195, 12.58747], [42.7996, 12.42629], [42.6957, 12.36201], [42.46941, 12.52661], [42.4037, 12.46478], [41.95461, 11.81157], [41.82878, 11.72361], [41.77727, 11.49902], [41.8096, 11.33606], [41.80056, 10.97127], [42.06302, 10.92599], [42.13691, 10.97586], [42.42669, 10.98493], [42.62989, 11.09711], [42.75111, 11.06992], [42.79037, 10.98493], [42.95776, 10.98533], [43.90659, 12.3823]]]]
23904           }
23905         }, {
23906           type: "Feature",
23907           properties: {
23908             iso1A2: "DK",
23909             iso1A3: "DNK",
23910             iso1N3: "208",
23911             wikidata: "Q756617",
23912             nameEn: "Kingdom of Denmark"
23913           },
23914           geometry: null
23915         }, {
23916           type: "Feature",
23917           properties: {
23918             iso1A2: "DM",
23919             iso1A3: "DMA",
23920             iso1N3: "212",
23921             wikidata: "Q784",
23922             nameEn: "Dominica",
23923             groups: ["029", "003", "419", "019", "UN"],
23924             driveSide: "left",
23925             roadSpeedUnit: "mph",
23926             callingCodes: ["1 767"]
23927           },
23928           geometry: {
23929             type: "MultiPolygon",
23930             coordinates: [[[[-61.32485, 14.91445], [-60.86656, 15.82603], [-61.95646, 15.5094], [-61.32485, 14.91445]]]]
23931           }
23932         }, {
23933           type: "Feature",
23934           properties: {
23935             iso1A2: "DO",
23936             iso1A3: "DOM",
23937             iso1N3: "214",
23938             wikidata: "Q786",
23939             nameEn: "Dominican Republic",
23940             groups: ["029", "003", "419", "019", "UN"],
23941             callingCodes: ["1 809", "1 829", "1 849"]
23942           },
23943           geometry: {
23944             type: "MultiPolygon",
23945             coordinates: [[[[-67.87844, 21.7938], [-72.38946, 20.27111], [-71.77419, 19.73128], [-71.75865, 19.70231], [-71.7429, 19.58445], [-71.71449, 19.55364], [-71.71268, 19.53374], [-71.6802, 19.45008], [-71.69448, 19.37866], [-71.77766, 19.33823], [-71.73229, 19.26686], [-71.62642, 19.21212], [-71.65337, 19.11759], [-71.69938, 19.10916], [-71.71088, 19.08353], [-71.74088, 19.0437], [-71.88102, 18.95007], [-71.77766, 18.95007], [-71.72624, 18.87802], [-71.71885, 18.78423], [-71.82556, 18.62551], [-71.95412, 18.64939], [-72.00201, 18.62312], [-71.88102, 18.50125], [-71.90875, 18.45821], [-71.69952, 18.34101], [-71.78271, 18.18302], [-71.75465, 18.14405], [-71.74994, 18.11115], [-71.73783, 18.07177], [-71.75671, 18.03456], [-72.29523, 17.48026], [-68.39466, 16.14167], [-67.87844, 21.7938]]]]
23946           }
23947         }, {
23948           type: "Feature",
23949           properties: {
23950             iso1A2: "DZ",
23951             iso1A3: "DZA",
23952             iso1N3: "012",
23953             wikidata: "Q262",
23954             nameEn: "Algeria",
23955             groups: ["015", "002", "UN"],
23956             callingCodes: ["213"]
23957           },
23958           geometry: {
23959             type: "MultiPolygon",
23960             coordinates: [[[[8.59123, 37.14286], [5.10072, 39.89531], [-2.27707, 35.35051], [-2.21248, 35.08532], [-2.21445, 35.04378], [-2.04734, 34.93218], [-1.97833, 34.93218], [-1.97469, 34.886], [-1.73707, 34.74226], [-1.84569, 34.61907], [-1.69788, 34.48056], [-1.78042, 34.39018], [-1.64666, 34.10405], [-1.73494, 33.71721], [-1.59508, 33.59929], [-1.67067, 33.27084], [-1.46249, 33.0499], [-1.54244, 32.95499], [-1.37794, 32.73628], [-0.9912, 32.52467], [-1.24998, 32.32993], [-1.24453, 32.1917], [-1.15735, 32.12096], [-1.22829, 32.07832], [-2.46166, 32.16603], [-2.93873, 32.06557], [-2.82784, 31.79459], [-3.66314, 31.6339], [-3.66386, 31.39202], [-3.77647, 31.31912], [-3.77103, 31.14984], [-3.54944, 31.0503], [-3.65418, 30.85566], [-3.64735, 30.67539], [-4.31774, 30.53229], [-4.6058, 30.28343], [-5.21671, 29.95253], [-5.58831, 29.48103], [-5.72121, 29.52322], [-5.75616, 29.61407], [-6.69965, 29.51623], [-6.78351, 29.44634], [-6.95824, 29.50924], [-7.61585, 29.36252], [-8.6715, 28.71194], [-8.66879, 27.6666], [-8.66674, 27.31569], [-4.83423, 24.99935], [1.15698, 21.12843], [1.20992, 20.73533], [3.24648, 19.81703], [3.12501, 19.1366], [3.36082, 18.9745], [4.26651, 19.14224], [5.8153, 19.45101], [7.38361, 20.79165], [7.48273, 20.87258], [11.96886, 23.51735], [11.62498, 24.26669], [11.41061, 24.21456], [10.85323, 24.5595], [10.33159, 24.5465], [10.02432, 24.98124], [10.03146, 25.35635], [9.38834, 26.19288], [9.51696, 26.39148], [9.89569, 26.57696], [9.78136, 29.40961], [9.3876, 30.16738], [9.55544, 30.23971], [9.07483, 32.07865], [8.35999, 32.50101], [8.31895, 32.83483], [8.1179, 33.05086], [8.11433, 33.10175], [7.83028, 33.18851], [7.73687, 33.42114], [7.54088, 33.7726], [7.52851, 34.06493], [7.66174, 34.20167], [7.74207, 34.16492], [7.81242, 34.21841], [7.86264, 34.3987], [8.20482, 34.57575], [8.29655, 34.72798], [8.25189, 34.92009], [8.30727, 34.95378], [8.3555, 35.10007], [8.47318, 35.23376], [8.30329, 35.29884], [8.36086, 35.47774], [8.35371, 35.66373], [8.26472, 35.73669], [8.2626, 35.91733], [8.40731, 36.42208], [8.18936, 36.44939], [8.16167, 36.48817], [8.47609, 36.66607], [8.46537, 36.7706], [8.57613, 36.78062], [8.67706, 36.8364], [8.62972, 36.86499], [8.64044, 36.9401], [8.59123, 37.14286]]]]
23961           }
23962         }, {
23963           type: "Feature",
23964           properties: {
23965             iso1A2: "EA",
23966             wikidata: "Q28868874",
23967             nameEn: "Ceuta, Melilla",
23968             country: "ES",
23969             level: "territory",
23970             isoStatus: "excRes"
23971           },
23972           geometry: null
23973         }, {
23974           type: "Feature",
23975           properties: {
23976             iso1A2: "EC",
23977             iso1A3: "ECU",
23978             iso1N3: "218",
23979             wikidata: "Q736",
23980             nameEn: "Ecuador"
23981           },
23982           geometry: null
23983         }, {
23984           type: "Feature",
23985           properties: {
23986             iso1A2: "EE",
23987             iso1A3: "EST",
23988             iso1N3: "233",
23989             wikidata: "Q191",
23990             nameEn: "Estonia",
23991             aliases: ["EW"],
23992             groups: ["EU", "154", "150", "UN"],
23993             callingCodes: ["372"]
23994           },
23995           geometry: {
23996             type: "MultiPolygon",
23997             coordinates: [[[[26.32936, 60.00121], [20.5104, 59.15546], [19.84909, 57.57876], [22.80496, 57.87798], [23.20055, 57.56697], [24.26221, 57.91787], [24.3579, 57.87471], [25.19484, 58.0831], [25.28237, 57.98539], [25.29581, 58.08288], [25.73499, 57.90193], [26.05949, 57.84744], [26.0324, 57.79037], [26.02456, 57.78342], [26.027, 57.78158], [26.0266, 57.77441], [26.02069, 57.77169], [26.02415, 57.76865], [26.03332, 57.7718], [26.0543, 57.76105], [26.08098, 57.76619], [26.2029, 57.7206], [26.1866, 57.6849], [26.29253, 57.59244], [26.46527, 57.56885], [26.54675, 57.51813], [26.90364, 57.62823], [27.34698, 57.52242], [27.31919, 57.57672], [27.40393, 57.62125], [27.3746, 57.66834], [27.52615, 57.72843], [27.50171, 57.78842], [27.56689, 57.83356], [27.78526, 57.83963], [27.81841, 57.89244], [27.67282, 57.92627], [27.62393, 58.09462], [27.48541, 58.22615], [27.55489, 58.39525], [27.36366, 58.78381], [27.74429, 58.98351], [27.80482, 59.1116], [27.87978, 59.18097], [27.90911, 59.24353], [28.00689, 59.28351], [28.14215, 59.28934], [28.19284, 59.35791], [28.20537, 59.36491], [28.21137, 59.38058], [28.19061, 59.39962], [28.04187, 59.47017], [27.85643, 59.58538], [26.90044, 59.63819], [26.32936, 60.00121]]]]
23998           }
23999         }, {
24000           type: "Feature",
24001           properties: {
24002             iso1A2: "EG",
24003             iso1A3: "EGY",
24004             iso1N3: "818",
24005             wikidata: "Q79",
24006             nameEn: "Egypt",
24007             groups: ["015", "002", "UN"],
24008             callingCodes: ["20"]
24009           },
24010           geometry: {
24011             type: "MultiPolygon",
24012             coordinates: [[[[33.62659, 31.82938], [26.92891, 33.39516], [24.8458, 31.39877], [25.01077, 30.73861], [24.71117, 30.17441], [24.99968, 29.24574], [24.99885, 21.99535], [33.17563, 22.00405], [34.0765, 22.00501], [37.8565, 22.00903], [34.4454, 27.91479], [34.8812, 29.36878], [34.92298, 29.45305], [34.26742, 31.21998], [34.24012, 31.29591], [34.23572, 31.2966], [34.21853, 31.32363], [34.052, 31.46619], [33.62659, 31.82938]]]]
24013           }
24014         }, {
24015           type: "Feature",
24016           properties: {
24017             iso1A2: "EH",
24018             iso1A3: "ESH",
24019             iso1N3: "732",
24020             wikidata: "Q6250",
24021             nameEn: "Western Sahara",
24022             groups: ["015", "002"],
24023             callingCodes: ["212"]
24024           },
24025           geometry: {
24026             type: "MultiPolygon",
24027             coordinates: [[[[-8.66879, 27.6666], [-8.77527, 27.66663], [-8.71787, 26.9898], [-9.08698, 26.98639], [-9.56957, 26.90042], [-9.81998, 26.71379], [-10.68417, 26.90984], [-11.35695, 26.8505], [-11.23622, 26.72023], [-11.38635, 26.611], [-11.62052, 26.05229], [-12.06001, 26.04442], [-12.12281, 25.13682], [-12.92147, 24.39502], [-13.00628, 24.01923], [-13.75627, 23.77231], [-14.10361, 22.75501], [-14.1291, 22.41636], [-14.48112, 22.00886], [-14.47329, 21.63839], [-14.78487, 21.36587], [-16.44269, 21.39745], [-16.9978, 21.36239], [-17.02707, 21.34022], [-17.21511, 21.34226], [-17.35589, 20.80492], [-17.0471, 20.76408], [-17.0695, 20.85742], [-17.06781, 20.92697], [-17.0396, 20.9961], [-17.0357, 21.05368], [-16.99806, 21.12142], [-16.95474, 21.33997], [-13.01525, 21.33343], [-13.08438, 22.53866], [-13.15313, 22.75649], [-13.10753, 22.89493], [-13.00412, 23.02297], [-12.5741, 23.28975], [-12.36213, 23.3187], [-12.14969, 23.41935], [-12.00251, 23.4538], [-12.0002, 25.9986], [-8.66721, 25.99918], [-8.66674, 27.31569], [-8.66879, 27.6666]]]]
24028           }
24029         }, {
24030           type: "Feature",
24031           properties: {
24032             iso1A2: "ER",
24033             iso1A3: "ERI",
24034             iso1N3: "232",
24035             wikidata: "Q986",
24036             nameEn: "Eritrea",
24037             groups: ["014", "202", "002", "UN"],
24038             callingCodes: ["291"]
24039           },
24040           geometry: {
24041             type: "MultiPolygon",
24042             coordinates: [[[[40.99158, 15.81743], [39.63762, 18.37348], [38.57727, 17.98125], [38.45916, 17.87167], [38.37133, 17.66269], [38.13362, 17.53906], [37.50967, 17.32199], [37.42694, 17.04041], [36.99777, 17.07172], [36.92193, 16.23451], [36.76371, 15.80831], [36.69761, 15.75323], [36.54276, 15.23478], [36.44337, 15.14963], [36.54376, 14.25597], [36.56536, 14.26177], [36.55659, 14.28237], [36.63364, 14.31172], [36.85787, 14.32201], [37.01622, 14.2561], [37.09486, 14.27155], [37.13206, 14.40746], [37.3106, 14.44657], [37.47319, 14.2149], [37.528, 14.18413], [37.91287, 14.89447], [38.0364, 14.72745], [38.25562, 14.67287], [38.3533, 14.51323], [38.45748, 14.41445], [38.78306, 14.4754], [38.98058, 14.54895], [39.02834, 14.63717], [39.16074, 14.65187], [39.14772, 14.61827], [39.19547, 14.56996], [39.23888, 14.56365], [39.26927, 14.48801], [39.2302, 14.44598], [39.2519, 14.40393], [39.37685, 14.54402], [39.52756, 14.49011], [39.50585, 14.55735], [39.58182, 14.60987], [39.76632, 14.54264], [39.9443, 14.41024], [40.07236, 14.54264], [40.14649, 14.53969], [40.21128, 14.39342], [40.25686, 14.41445], [40.9167, 14.11152], [41.25097, 13.60787], [41.62864, 13.38626], [42.05841, 12.80912], [42.21469, 12.75832], [42.2798, 12.6355], [42.4037, 12.46478], [42.46941, 12.52661], [42.6957, 12.36201], [42.7996, 12.42629], [42.86195, 12.58747], [43.29075, 12.79154], [40.99158, 15.81743]]]]
24043           }
24044         }, {
24045           type: "Feature",
24046           properties: {
24047             iso1A2: "ES",
24048             iso1A3: "ESP",
24049             iso1N3: "724",
24050             wikidata: "Q29",
24051             nameEn: "Spain"
24052           },
24053           geometry: null
24054         }, {
24055           type: "Feature",
24056           properties: {
24057             iso1A2: "ET",
24058             iso1A3: "ETH",
24059             iso1N3: "231",
24060             wikidata: "Q115",
24061             nameEn: "Ethiopia",
24062             groups: ["014", "202", "002", "UN"],
24063             callingCodes: ["251"]
24064           },
24065           geometry: {
24066             type: "MultiPolygon",
24067             coordinates: [[[[42.4037, 12.46478], [42.2798, 12.6355], [42.21469, 12.75832], [42.05841, 12.80912], [41.62864, 13.38626], [41.25097, 13.60787], [40.9167, 14.11152], [40.25686, 14.41445], [40.21128, 14.39342], [40.14649, 14.53969], [40.07236, 14.54264], [39.9443, 14.41024], [39.76632, 14.54264], [39.58182, 14.60987], [39.50585, 14.55735], [39.52756, 14.49011], [39.37685, 14.54402], [39.2519, 14.40393], [39.2302, 14.44598], [39.26927, 14.48801], [39.23888, 14.56365], [39.19547, 14.56996], [39.14772, 14.61827], [39.16074, 14.65187], [39.02834, 14.63717], [38.98058, 14.54895], [38.78306, 14.4754], [38.45748, 14.41445], [38.3533, 14.51323], [38.25562, 14.67287], [38.0364, 14.72745], [37.91287, 14.89447], [37.528, 14.18413], [37.47319, 14.2149], [37.3106, 14.44657], [37.13206, 14.40746], [37.09486, 14.27155], [37.01622, 14.2561], [36.85787, 14.32201], [36.63364, 14.31172], [36.55659, 14.28237], [36.56536, 14.26177], [36.54376, 14.25597], [36.44653, 13.95666], [36.48824, 13.83954], [36.38993, 13.56459], [36.24545, 13.36759], [36.13374, 12.92665], [36.16651, 12.88019], [36.14268, 12.70879], [36.01458, 12.72478], [35.70476, 12.67101], [35.24302, 11.91132], [35.11492, 11.85156], [35.05832, 11.71158], [35.09556, 11.56278], [34.95704, 11.24448], [35.01215, 11.19626], [34.93172, 10.95946], [34.97789, 10.91559], [34.97491, 10.86147], [34.86916, 10.78832], [34.86618, 10.74588], [34.77532, 10.69027], [34.77383, 10.74588], [34.59062, 10.89072], [34.4372, 10.781], [34.2823, 10.53508], [34.34783, 10.23914], [34.32102, 10.11599], [34.22718, 10.02506], [34.20484, 9.9033], [34.13186, 9.7492], [34.08717, 9.55243], [34.10229, 9.50238], [34.14304, 9.04654], [34.14453, 8.60204], [34.01346, 8.50041], [33.89579, 8.4842], [33.87195, 8.41938], [33.71407, 8.3678], [33.66938, 8.44442], [33.54575, 8.47094], [33.3119, 8.45474], [33.19721, 8.40317], [33.1853, 8.29264], [33.18083, 8.13047], [33.08401, 8.05822], [33.0006, 7.90333], [33.04944, 7.78989], [33.24637, 7.77939], [33.32531, 7.71297], [33.44745, 7.7543], [33.71407, 7.65983], [33.87642, 7.5491], [34.02984, 7.36449], [34.03878, 7.27437], [34.01495, 7.25664], [34.19369, 7.12807], [34.19369, 7.04382], [34.35753, 6.91963], [34.47669, 6.91076], [34.53925, 6.82794], [34.53776, 6.74808], [34.65096, 6.72589], [34.77459, 6.5957], [34.87736, 6.60161], [35.01738, 6.46991], [34.96227, 6.26415], [35.00546, 5.89387], [35.12611, 5.68937], [35.13058, 5.62118], [35.31188, 5.50106], [35.29938, 5.34042], [35.50792, 5.42431], [35.8576, 5.33413], [35.81968, 5.10757], [35.82118, 4.77382], [35.9419, 4.61933], [35.95449, 4.53244], [36.03924, 4.44406], [36.84474, 4.44518], [37.07724, 4.33503], [38.14168, 3.62487], [38.45812, 3.60445], [38.52336, 3.62551], [38.91938, 3.51198], [39.07736, 3.5267], [39.19954, 3.47834], [39.49444, 3.45521], [39.51551, 3.40895], [39.55132, 3.39634], [39.58339, 3.47434], [39.76808, 3.67058], [39.86043, 3.86974], [40.77498, 4.27683], [41.1754, 3.94079], [41.89488, 3.97375], [42.07619, 4.17667], [42.55853, 4.20518], [42.84526, 4.28357], [42.97746, 4.44032], [43.04177, 4.57923], [43.40263, 4.79289], [44.02436, 4.9451], [44.98104, 4.91821], [47.97917, 8.00124], [47.92477, 8.00111], [46.99339, 7.9989], [44.19222, 8.93028], [43.32613, 9.59205], [43.23518, 9.84605], [43.0937, 9.90579], [42.87643, 10.18441], [42.69452, 10.62672], [42.95776, 10.98533], [42.79037, 10.98493], [42.75111, 11.06992], [42.62989, 11.09711], [42.42669, 10.98493], [42.13691, 10.97586], [42.06302, 10.92599], [41.80056, 10.97127], [41.8096, 11.33606], [41.77727, 11.49902], [41.82878, 11.72361], [41.95461, 11.81157], [42.4037, 12.46478]]]]
24068           }
24069         }, {
24070           type: "Feature",
24071           properties: {
24072             iso1A2: "EU",
24073             iso1A3: "EUE",
24074             wikidata: "Q458",
24075             nameEn: "European Union",
24076             level: "union",
24077             isoStatus: "excRes"
24078           },
24079           geometry: null
24080         }, {
24081           type: "Feature",
24082           properties: {
24083             iso1A2: "FI",
24084             iso1A3: "FIN",
24085             iso1N3: "246",
24086             wikidata: "Q33",
24087             nameEn: "Finland",
24088             aliases: ["SF"]
24089           },
24090           geometry: null
24091         }, {
24092           type: "Feature",
24093           properties: {
24094             iso1A2: "FJ",
24095             iso1A3: "FJI",
24096             iso1N3: "242",
24097             wikidata: "Q712",
24098             nameEn: "Fiji",
24099             groups: ["054", "009", "UN"],
24100             driveSide: "left",
24101             callingCodes: ["679"]
24102           },
24103           geometry: {
24104             type: "MultiPolygon",
24105             coordinates: [[[[174.245, -23.1974], [179.99999, -22.5], [179.99999, -11.5], [174, -11.5], [174.245, -23.1974]]], [[[-176.76826, -14.95183], [-180, -14.96041], [-180, -22.90585], [-176.74538, -22.89767], [-176.76826, -14.95183]]]]
24106           }
24107         }, {
24108           type: "Feature",
24109           properties: {
24110             iso1A2: "FK",
24111             iso1A3: "FLK",
24112             iso1N3: "238",
24113             wikidata: "Q9648",
24114             nameEn: "Falkland Islands",
24115             country: "GB",
24116             groups: ["BOTS", "005", "419", "019", "UN"],
24117             driveSide: "left",
24118             roadSpeedUnit: "mph",
24119             roadHeightUnit: "ft",
24120             callingCodes: ["500"]
24121           },
24122           geometry: {
24123             type: "MultiPolygon",
24124             coordinates: [[[[-63.67376, -55.11859], [-54.56126, -51.26248], [-61.26735, -50.63919], [-63.67376, -55.11859]]]]
24125           }
24126         }, {
24127           type: "Feature",
24128           properties: {
24129             iso1A2: "FM",
24130             iso1A3: "FSM",
24131             iso1N3: "583",
24132             wikidata: "Q702",
24133             nameEn: "Federated States of Micronesia",
24134             groups: ["057", "009", "UN"],
24135             roadSpeedUnit: "mph",
24136             roadHeightUnit: "ft",
24137             callingCodes: ["691"]
24138           },
24139           geometry: {
24140             type: "MultiPolygon",
24141             coordinates: [[[[138.20583, 13.3783], [136.27107, 6.73747], [156.88247, -1.39237], [165.19726, 6.22546], [138.20583, 13.3783]]]]
24142           }
24143         }, {
24144           type: "Feature",
24145           properties: {
24146             iso1A2: "FO",
24147             iso1A3: "FRO",
24148             iso1N3: "234",
24149             wikidata: "Q4628",
24150             nameEn: "Faroe Islands",
24151             country: "DK",
24152             groups: ["154", "150", "UN"],
24153             callingCodes: ["298"]
24154           },
24155           geometry: {
24156             type: "MultiPolygon",
24157             coordinates: [[[[-8.51774, 62.35338], [-6.51083, 60.95272], [-5.70102, 62.77194], [-8.51774, 62.35338]]]]
24158           }
24159         }, {
24160           type: "Feature",
24161           properties: {
24162             iso1A2: "FR",
24163             iso1A3: "FRA",
24164             iso1N3: "250",
24165             wikidata: "Q142",
24166             nameEn: "France"
24167           },
24168           geometry: null
24169         }, {
24170           type: "Feature",
24171           properties: {
24172             iso1A2: "FX",
24173             iso1A3: "FXX",
24174             iso1N3: "249",
24175             wikidata: "Q212429",
24176             nameEn: "Metropolitan France",
24177             country: "FR",
24178             groups: ["EU", "155", "150", "UN"],
24179             isoStatus: "excRes",
24180             callingCodes: ["33"]
24181           },
24182           geometry: {
24183             type: "MultiPolygon",
24184             coordinates: [[[[2.55904, 51.07014], [2.18458, 51.52087], [1.17405, 50.74239], [-2.02963, 49.91866], [-2.09454, 49.46288], [-1.83944, 49.23037], [-2.00491, 48.86706], [-2.65349, 49.15373], [-6.28985, 48.93406], [-1.81005, 43.59738], [-1.77289, 43.38957], [-1.79319, 43.37497], [-1.78332, 43.36399], [-1.78714, 43.35476], [-1.77068, 43.34396], [-1.75334, 43.34107], [-1.75079, 43.3317], [-1.7397, 43.32979], [-1.73074, 43.29481], [-1.69407, 43.31378], [-1.62481, 43.30726], [-1.63052, 43.28591], [-1.61341, 43.25269], [-1.57674, 43.25269], [-1.55963, 43.28828], [-1.50992, 43.29481], [-1.45289, 43.27049], [-1.40942, 43.27272], [-1.3758, 43.24511], [-1.41562, 43.12815], [-1.47555, 43.08372], [-1.44067, 43.047], [-1.35272, 43.02658], [-1.34419, 43.09665], [-1.32209, 43.1127], [-1.27118, 43.11961], [-1.30052, 43.09581], [-1.30531, 43.06859], [-1.25244, 43.04164], [-1.22881, 43.05534], [-1.10333, 43.0059], [-1.00963, 42.99279], [-0.97133, 42.96239], [-0.81652, 42.95166], [-0.75478, 42.96916], [-0.72037, 42.92541], [-0.73422, 42.91228], [-0.72608, 42.89318], [-0.69837, 42.87945], [-0.67637, 42.88303], [-0.55497, 42.77846], [-0.50863, 42.82713], [-0.44334, 42.79939], [-0.41319, 42.80776], [-0.38833, 42.80132], [-0.3122, 42.84788], [-0.17939, 42.78974], [-0.16141, 42.79535], [-0.10519, 42.72761], [-0.02468, 42.68513], [0.17569, 42.73424], [0.25336, 42.7174], [0.29407, 42.67431], [0.36251, 42.72282], [0.40214, 42.69779], [0.67873, 42.69458], [0.65421, 42.75872], [0.66121, 42.84021], [0.711, 42.86372], [0.93089, 42.79154], [0.96166, 42.80629], [0.98292, 42.78754], [1.0804, 42.78569], [1.15928, 42.71407], [1.35562, 42.71944], [1.44197, 42.60217], [1.47986, 42.61346], [1.46718, 42.63296], [1.48043, 42.65203], [1.50867, 42.64483], [1.55418, 42.65669], [1.60085, 42.62703], [1.63485, 42.62957], [1.6625, 42.61982], [1.68267, 42.62533], [1.73452, 42.61515], [1.72588, 42.59098], [1.7858, 42.57698], [1.73683, 42.55492], [1.72515, 42.50338], [1.76335, 42.48863], [1.83037, 42.48395], [1.88853, 42.4501], [1.93663, 42.45439], [1.94292, 42.44316], [1.94061, 42.43333], [1.94084, 42.43039], [1.9574, 42.42401], [1.96482, 42.37787], [2.00488, 42.35399], [2.06241, 42.35906], [2.11621, 42.38393], [2.12789, 42.41291], [2.16599, 42.42314], [2.20578, 42.41633], [2.25551, 42.43757], [2.38504, 42.39977], [2.43299, 42.39423], [2.43508, 42.37568], [2.48457, 42.33933], [2.54382, 42.33406], [2.55516, 42.35351], [2.57934, 42.35808], [2.6747, 42.33974], [2.65311, 42.38771], [2.72056, 42.42298], [2.75497, 42.42578], [2.77464, 42.41046], [2.84335, 42.45724], [2.85675, 42.45444], [2.86983, 42.46843], [2.88413, 42.45938], [2.92107, 42.4573], [2.94283, 42.48174], [2.96518, 42.46692], [3.03734, 42.47363], [3.08167, 42.42748], [3.10027, 42.42621], [3.11379, 42.43646], [3.17156, 42.43545], [3.75438, 42.33445], [7.60802, 41.05927], [10.09675, 41.44089], [9.56115, 43.20816], [7.50102, 43.51859], [7.42422, 43.72209], [7.40903, 43.7296], [7.41113, 43.73156], [7.41291, 43.73168], [7.41298, 43.73311], [7.41233, 43.73439], [7.42062, 43.73977], [7.42299, 43.74176], [7.42443, 43.74087], [7.42809, 43.74396], [7.43013, 43.74895], [7.43624, 43.75014], [7.43708, 43.75197], [7.4389, 43.75151], [7.4379, 43.74963], [7.47823, 43.73341], [7.53006, 43.78405], [7.50423, 43.84345], [7.49355, 43.86551], [7.51162, 43.88301], [7.56075, 43.89932], [7.56858, 43.94506], [7.60771, 43.95772], [7.65266, 43.9763], [7.66848, 43.99943], [7.6597, 44.03009], [7.72508, 44.07578], [7.66878, 44.12795], [7.68694, 44.17487], [7.63245, 44.17877], [7.62155, 44.14881], [7.36364, 44.11882], [7.34547, 44.14359], [7.27827, 44.1462], [7.16929, 44.20352], [7.00764, 44.23736], [6.98221, 44.28289], [6.89171, 44.36637], [6.88784, 44.42043], [6.94504, 44.43112], [6.86233, 44.49834], [6.85507, 44.53072], [6.96042, 44.62129], [6.95133, 44.66264], [7.00582, 44.69364], [7.07484, 44.68073], [7.00401, 44.78782], [7.02217, 44.82519], [6.93499, 44.8664], [6.90774, 44.84322], [6.75518, 44.89915], [6.74519, 44.93661], [6.74791, 45.01939], [6.66981, 45.02324], [6.62803, 45.11175], [6.7697, 45.16044], [6.85144, 45.13226], [6.96706, 45.20841], [7.07074, 45.21228], [7.13115, 45.25386], [7.10572, 45.32924], [7.18019, 45.40071], [7.00037, 45.509], [6.98948, 45.63869], [6.80785, 45.71864], [6.80785, 45.83265], [6.95315, 45.85163], [7.04151, 45.92435], [7.00946, 45.9944], [6.93862, 46.06502], [6.87868, 46.03855], [6.89321, 46.12548], [6.78968, 46.14058], [6.86052, 46.28512], [6.77152, 46.34784], [6.8024, 46.39171], [6.82312, 46.42661], [6.53358, 46.45431], [6.25432, 46.3632], [6.21981, 46.31304], [6.24826, 46.30175], [6.25137, 46.29014], [6.23775, 46.27822], [6.24952, 46.26255], [6.26749, 46.24745], [6.29474, 46.26221], [6.31041, 46.24417], [6.29663, 46.22688], [6.27694, 46.21566], [6.26007, 46.21165], [6.24821, 46.20531], [6.23913, 46.20511], [6.23544, 46.20714], [6.22175, 46.20045], [6.22222, 46.19888], [6.21844, 46.19837], [6.21603, 46.19507], [6.21273, 46.19409], [6.21114, 46.1927], [6.20539, 46.19163], [6.19807, 46.18369], [6.19552, 46.18401], [6.18707, 46.17999], [6.18871, 46.16644], [6.18116, 46.16187], [6.15305, 46.15194], [6.13397, 46.1406], [6.09926, 46.14373], [6.09199, 46.15191], [6.07491, 46.14879], [6.05203, 46.15191], [6.04564, 46.14031], [6.03614, 46.13712], [6.01791, 46.14228], [5.9871, 46.14499], [5.97893, 46.13303], [5.95781, 46.12925], [5.9641, 46.14412], [5.97508, 46.15863], [5.98188, 46.17392], [5.98846, 46.17046], [5.99573, 46.18587], [5.96515, 46.19638], [5.97542, 46.21525], [6.02461, 46.23313], [6.03342, 46.2383], [6.04602, 46.23127], [6.05029, 46.23518], [6.0633, 46.24583], [6.07072, 46.24085], [6.08563, 46.24651], [6.10071, 46.23772], [6.12446, 46.25059], [6.11926, 46.2634], [6.1013, 46.28512], [6.11697, 46.29547], [6.1198, 46.31157], [6.13876, 46.33844], [6.15738, 46.3491], [6.16987, 46.36759], [6.15985, 46.37721], [6.15016, 46.3778], [6.09926, 46.40768], [6.06407, 46.41676], [6.08427, 46.44305], [6.07269, 46.46244], [6.1567, 46.54402], [6.11084, 46.57649], [6.27135, 46.68251], [6.38351, 46.73171], [6.45209, 46.77502], [6.43216, 46.80336], [6.46456, 46.88865], [6.43341, 46.92703], [6.71531, 47.0494], [6.68823, 47.06616], [6.76788, 47.1208], [6.8489, 47.15933], [6.9508, 47.24338], [6.95108, 47.26428], [6.94316, 47.28747], [7.05305, 47.33304], [7.0564, 47.35134], [7.03125, 47.36996], [6.87959, 47.35335], [6.88542, 47.37262], [6.93744, 47.40714], [6.93953, 47.43388], [7.0024, 47.45264], [6.98425, 47.49432], [7.0231, 47.50522], [7.07425, 47.48863], [7.12781, 47.50371], [7.16249, 47.49025], [7.19583, 47.49455], [7.17026, 47.44312], [7.24669, 47.4205], [7.33526, 47.44186], [7.35603, 47.43432], [7.40308, 47.43638], [7.43088, 47.45846], [7.4462, 47.46264], [7.4583, 47.47216], [7.42923, 47.48628], [7.43356, 47.49712], [7.47534, 47.47932], [7.51076, 47.49651], [7.49804, 47.51798], [7.5229, 47.51644], [7.53199, 47.5284], [7.51904, 47.53515], [7.50588, 47.52856], [7.49691, 47.53821], [7.50873, 47.54546], [7.51723, 47.54578], [7.52831, 47.55347], [7.53634, 47.55553], [7.55652, 47.56779], [7.55689, 47.57232], [7.56548, 47.57617], [7.56684, 47.57785], [7.58386, 47.57536], [7.58945, 47.59017], [7.59301, 47.60058], [7.58851, 47.60794], [7.57423, 47.61628], [7.5591, 47.63849], [7.53384, 47.65115], [7.52067, 47.66437], [7.51915, 47.68335], [7.51266, 47.70197], [7.53722, 47.71635], [7.54761, 47.72912], [7.52921, 47.77747], [7.55673, 47.87371], [7.62302, 47.97898], [7.56966, 48.03265], [7.57137, 48.12292], [7.6648, 48.22219], [7.69022, 48.30018], [7.74562, 48.32736], [7.73109, 48.39192], [7.76833, 48.48945], [7.80647, 48.51239], [7.80167, 48.54758], [7.80057, 48.5857], [7.84098, 48.64217], [7.89002, 48.66317], [7.96812, 48.72491], [7.96994, 48.75606], [8.01534, 48.76085], [8.0326, 48.79017], [8.06802, 48.78957], [8.10253, 48.81829], [8.12813, 48.87985], [8.19989, 48.95825], [8.20031, 48.95856], [8.22604, 48.97352], [8.14189, 48.97833], [7.97783, 49.03161], [7.93641, 49.05544], [7.86386, 49.03499], [7.79557, 49.06583], [7.75948, 49.04562], [7.63618, 49.05428], [7.62575, 49.07654], [7.56416, 49.08136], [7.53012, 49.09818], [7.49172, 49.13915], [7.49473, 49.17], [7.44455, 49.16765], [7.44052, 49.18354], [7.3662, 49.17308], [7.35995, 49.14399], [7.3195, 49.14231], [7.29514, 49.11426], [7.23473, 49.12971], [7.1593, 49.1204], [7.1358, 49.1282], [7.12504, 49.14253], [7.10384, 49.13787], [7.10715, 49.15631], [7.07859, 49.15031], [7.09007, 49.13094], [7.07162, 49.1255], [7.06642, 49.11415], [7.05548, 49.11185], [7.04843, 49.11422], [7.04409, 49.12123], [7.04662, 49.13724], [7.03178, 49.15734], [7.0274, 49.17042], [7.03459, 49.19096], [7.01318, 49.19018], [6.97273, 49.2099], [6.95963, 49.203], [6.94028, 49.21641], [6.93831, 49.2223], [6.91875, 49.22261], [6.89298, 49.20863], [6.85939, 49.22376], [6.83555, 49.21249], [6.85119, 49.20038], [6.85016, 49.19354], [6.86225, 49.18185], [6.84703, 49.15734], [6.83385, 49.15162], [6.78265, 49.16793], [6.73765, 49.16375], [6.71137, 49.18808], [6.73256, 49.20486], [6.71843, 49.2208], [6.69274, 49.21661], [6.66583, 49.28065], [6.60186, 49.31055], [6.572, 49.35027], [6.58807, 49.35358], [6.60091, 49.36864], [6.533, 49.40748], [6.55404, 49.42464], [6.42432, 49.47683], [6.40274, 49.46546], [6.39168, 49.4667], [6.38352, 49.46463], [6.36778, 49.46937], [6.3687, 49.4593], [6.28818, 49.48465], [6.27875, 49.503], [6.25029, 49.50609], [6.2409, 49.51408], [6.19543, 49.50536], [6.17386, 49.50934], [6.15366, 49.50226], [6.16115, 49.49297], [6.14321, 49.48796], [6.12814, 49.49365], [6.12346, 49.4735], [6.10325, 49.4707], [6.09845, 49.46351], [6.10072, 49.45268], [6.08373, 49.45594], [6.07887, 49.46399], [6.05553, 49.46663], [6.04176, 49.44801], [6.02743, 49.44845], [6.02648, 49.45451], [5.97693, 49.45513], [5.96876, 49.49053], [5.94224, 49.49608], [5.94128, 49.50034], [5.86571, 49.50015], [5.83389, 49.52152], [5.83467, 49.52717], [5.84466, 49.53027], [5.83648, 49.5425], [5.81664, 49.53775], [5.80871, 49.5425], [5.81838, 49.54777], [5.79195, 49.55228], [5.77435, 49.56298], [5.7577, 49.55915], [5.75649, 49.54321], [5.64505, 49.55146], [5.60909, 49.51228], [5.55001, 49.52729], [5.46541, 49.49825], [5.46734, 49.52648], [5.43713, 49.5707], [5.3974, 49.61596], [5.34837, 49.62889], [5.33851, 49.61599], [5.3137, 49.61225], [5.30214, 49.63055], [5.33039, 49.6555], [5.31465, 49.66846], [5.26232, 49.69456], [5.14545, 49.70287], [5.09249, 49.76193], [4.96714, 49.79872], [4.85464, 49.78995], [4.86965, 49.82271], [4.85134, 49.86457], [4.88529, 49.9236], [4.78827, 49.95609], [4.8382, 50.06738], [4.88602, 50.15182], [4.83279, 50.15331], [4.82438, 50.16878], [4.75237, 50.11314], [4.70064, 50.09384], [4.68695, 49.99685], [4.5414, 49.96911], [4.51098, 49.94659], [4.43488, 49.94122], [4.35051, 49.95315], [4.31963, 49.97043], [4.20532, 49.95803], [4.14239, 49.98034], [4.13508, 50.01976], [4.16294, 50.04719], [4.23101, 50.06945], [4.20147, 50.13535], [4.13561, 50.13078], [4.16014, 50.19239], [4.15524, 50.21103], [4.21945, 50.25539], [4.20651, 50.27333], [4.17861, 50.27443], [4.17347, 50.28838], [4.15524, 50.2833], [4.16808, 50.25786], [4.13665, 50.25609], [4.11954, 50.30425], [4.10957, 50.30234], [4.10237, 50.31247], [4.0689, 50.3254], [4.0268, 50.35793], [3.96771, 50.34989], [3.90781, 50.32814], [3.84314, 50.35219], [3.73911, 50.34809], [3.70987, 50.3191], [3.71009, 50.30305], [3.66976, 50.34563], [3.65709, 50.36873], [3.67262, 50.38663], [3.67494, 50.40239], [3.66153, 50.45165], [3.64426, 50.46275], [3.61014, 50.49568], [3.58361, 50.49049], [3.5683, 50.50192], [3.49509, 50.48885], [3.51564, 50.5256], [3.47385, 50.53397], [3.44629, 50.51009], [3.37693, 50.49538], [3.28575, 50.52724], [3.2729, 50.60718], [3.23951, 50.6585], [3.264, 50.67668], [3.2536, 50.68977], [3.26141, 50.69151], [3.26063, 50.70086], [3.24593, 50.71389], [3.22042, 50.71019], [3.20845, 50.71662], [3.19017, 50.72569], [3.20064, 50.73547], [3.18811, 50.74025], [3.18339, 50.74981], [3.16476, 50.76843], [3.15017, 50.79031], [3.1257, 50.78603], [3.11987, 50.79188], [3.11206, 50.79416], [3.10614, 50.78303], [3.09163, 50.77717], [3.04314, 50.77674], [3.00537, 50.76588], [2.96778, 50.75242], [2.95019, 50.75138], [2.90873, 50.702], [2.91036, 50.6939], [2.90069, 50.69263], [2.88504, 50.70656], [2.87937, 50.70298], [2.86985, 50.7033], [2.8483, 50.72276], [2.81056, 50.71773], [2.71165, 50.81295], [2.63331, 50.81457], [2.59093, 50.91751], [2.63074, 50.94746], [2.57551, 51.00326], [2.55904, 51.07014]], [[1.99838, 42.44682], [1.98378, 42.44697], [1.96125, 42.45364], [1.95606, 42.45785], [1.96215, 42.47854], [1.97003, 42.48081], [1.97227, 42.48487], [1.97697, 42.48568], [1.98022, 42.49569], [1.98916, 42.49351], [1.99766, 42.4858], [1.98579, 42.47486], [1.99216, 42.46208], [2.01564, 42.45171], [1.99838, 42.44682]]]]
24185           }
24186         }, {
24187           type: "Feature",
24188           properties: {
24189             iso1A2: "GA",
24190             iso1A3: "GAB",
24191             iso1N3: "266",
24192             wikidata: "Q1000",
24193             nameEn: "Gabon",
24194             groups: ["017", "202", "002", "UN"],
24195             callingCodes: ["241"]
24196           },
24197           geometry: {
24198             type: "MultiPolygon",
24199             coordinates: [[[[13.29457, 2.16106], [13.28534, 2.25716], [11.37116, 2.29975], [11.3561, 2.17217], [11.35307, 1.00251], [9.79648, 1.0019], [9.75065, 1.06753], [9.66433, 1.06723], [7.24416, -0.64092], [10.75913, -4.39519], [11.12647, -3.94169], [11.22301, -3.69888], [11.48764, -3.51089], [11.57949, -3.52798], [11.68608, -3.68942], [11.87083, -3.71571], [11.92719, -3.62768], [11.8318, -3.5812], [11.96554, -3.30267], [11.70227, -3.17465], [11.70558, -3.0773], [11.80365, -3.00424], [11.64798, -2.81146], [11.5359, -2.85654], [11.64487, -2.61865], [11.57637, -2.33379], [11.74605, -2.39936], [11.96866, -2.33559], [12.04895, -2.41704], [12.47925, -2.32626], [12.44656, -1.92025], [12.61312, -1.8129], [12.82172, -1.91091], [13.02759, -2.33098], [13.47977, -2.43224], [13.75884, -2.09293], [13.92073, -2.35581], [13.85846, -2.46935], [14.10442, -2.49268], [14.23829, -2.33715], [14.16202, -2.23916], [14.23518, -2.15671], [14.25932, -1.97624], [14.41838, -1.89412], [14.52569, -0.57818], [14.41887, -0.44799], [14.2165, -0.38261], [14.06862, -0.20826], [13.90632, -0.2287], [13.88648, 0.26652], [14.10909, 0.58563], [14.26066, 0.57255], [14.48179, 0.9152], [14.25186, 1.39842], [13.89582, 1.4261], [13.15519, 1.23368], [13.25447, 1.32339], [13.13461, 1.57238], [13.29457, 2.16106]]]]
24200           }
24201         }, {
24202           type: "Feature",
24203           properties: {
24204             iso1A2: "GB",
24205             iso1A3: "GBR",
24206             iso1N3: "826",
24207             wikidata: "Q145",
24208             ccTLD: ".uk",
24209             nameEn: "United Kingdom",
24210             aliases: ["UK"]
24211           },
24212           geometry: null
24213         }, {
24214           type: "Feature",
24215           properties: {
24216             iso1A2: "GD",
24217             iso1A3: "GRD",
24218             iso1N3: "308",
24219             wikidata: "Q769",
24220             nameEn: "Grenada",
24221             aliases: ["WG"],
24222             groups: ["029", "003", "419", "019", "UN"],
24223             driveSide: "left",
24224             roadSpeedUnit: "mph",
24225             callingCodes: ["1 473"]
24226           },
24227           geometry: {
24228             type: "MultiPolygon",
24229             coordinates: [[[[-62.64026, 12.69984], [-61.77886, 11.36496], [-59.94058, 12.34011], [-62.64026, 12.69984]]]]
24230           }
24231         }, {
24232           type: "Feature",
24233           properties: {
24234             iso1A2: "GE",
24235             iso1A3: "GEO",
24236             iso1N3: "268",
24237             wikidata: "Q230",
24238             nameEn: "Georgia",
24239             groups: ["145", "142", "UN"],
24240             callingCodes: ["995"]
24241           },
24242           geometry: {
24243             type: "MultiPolygon",
24244             coordinates: [[[[46.42738, 41.91323], [45.61676, 42.20768], [45.78692, 42.48358], [45.36501, 42.55268], [45.15318, 42.70598], [44.88754, 42.74934], [44.80941, 42.61277], [44.70002, 42.74679], [44.54202, 42.75699], [43.95517, 42.55396], [43.73119, 42.62043], [43.81453, 42.74297], [43.0419, 43.02413], [43.03322, 43.08883], [42.75889, 43.19651], [42.66667, 43.13917], [42.40563, 43.23226], [41.64935, 43.22331], [40.65957, 43.56212], [40.10657, 43.57344], [40.04445, 43.47776], [40.03312, 43.44262], [40.01007, 43.42411], [40.01552, 43.42025], [40.00853, 43.40578], [40.0078, 43.38551], [39.81147, 43.06294], [40.89217, 41.72528], [41.54366, 41.52185], [41.7148, 41.4932], [41.7124, 41.47417], [41.81939, 41.43621], [41.95134, 41.52466], [42.26387, 41.49346], [42.51772, 41.43606], [42.59202, 41.58183], [42.72794, 41.59714], [42.84471, 41.58912], [42.78995, 41.50126], [42.84899, 41.47265], [42.8785, 41.50516], [43.02956, 41.37891], [43.21707, 41.30331], [43.13373, 41.25503], [43.1945, 41.25242], [43.23096, 41.17536], [43.36118, 41.2028], [43.44973, 41.17666], [43.4717, 41.12611], [43.67712, 41.13398], [43.74717, 41.1117], [43.84835, 41.16329], [44.16591, 41.19141], [44.18148, 41.24644], [44.32139, 41.2079], [44.34337, 41.20312], [44.34417, 41.2382], [44.46791, 41.18204], [44.59322, 41.1933], [44.61462, 41.24018], [44.72814, 41.20338], [44.82084, 41.21513], [44.87887, 41.20195], [44.89911, 41.21366], [44.84358, 41.23088], [44.81749, 41.23488], [44.80053, 41.25949], [44.81437, 41.30371], [44.93493, 41.25685], [45.0133, 41.29747], [45.09867, 41.34065], [45.1797, 41.42231], [45.26285, 41.46433], [45.31352, 41.47168], [45.4006, 41.42402], [45.45973, 41.45898], [45.68389, 41.3539], [45.71035, 41.36208], [45.75705, 41.35157], [45.69946, 41.29545], [45.80842, 41.2229], [45.95786, 41.17956], [46.13221, 41.19479], [46.27698, 41.19011], [46.37661, 41.10805], [46.456, 41.09984], [46.48558, 41.0576], [46.55096, 41.1104], [46.63969, 41.09515], [46.66148, 41.20533], [46.72375, 41.28609], [46.63658, 41.37727], [46.4669, 41.43331], [46.40307, 41.48464], [46.33925, 41.4963], [46.29794, 41.5724], [46.34126, 41.57454], [46.34039, 41.5947], [46.3253, 41.60912], [46.28182, 41.60089], [46.26531, 41.63339], [46.24429, 41.59883], [46.19759, 41.62327], [46.17891, 41.72094], [46.20538, 41.77205], [46.23962, 41.75811], [46.30863, 41.79133], [46.3984, 41.84399], [46.42738, 41.91323]]]]
24245           }
24246         }, {
24247           type: "Feature",
24248           properties: {
24249             iso1A2: "GF",
24250             iso1A3: "GUF",
24251             iso1N3: "254",
24252             wikidata: "Q3769",
24253             nameEn: "French Guiana",
24254             country: "FR",
24255             groups: ["Q3320166", "EU", "005", "419", "019", "UN"],
24256             callingCodes: ["594"]
24257           },
24258           geometry: {
24259             type: "MultiPolygon",
24260             coordinates: [[[[-51.35485, 4.8383], [-53.7094, 6.2264], [-54.01074, 5.68785], [-54.01877, 5.52789], [-54.26916, 5.26909], [-54.4717, 4.91964], [-54.38444, 4.13222], [-54.19367, 3.84387], [-54.05128, 3.63557], [-53.98914, 3.627], [-53.9849, 3.58697], [-54.28534, 2.67798], [-54.42864, 2.42442], [-54.6084, 2.32856], [-54.16286, 2.10779], [-53.78743, 2.34412], [-52.96539, 2.1881], [-52.6906, 2.37298], [-52.31787, 3.17896], [-51.85573, 3.83427], [-51.82312, 3.85825], [-51.79599, 3.89336], [-51.61983, 4.14596], [-51.63798, 4.51394], [-51.35485, 4.8383]]]]
24261           }
24262         }, {
24263           type: "Feature",
24264           properties: {
24265             iso1A2: "GG",
24266             iso1A3: "GGY",
24267             iso1N3: "831",
24268             wikidata: "Q25230",
24269             nameEn: "Bailiwick of Guernsey",
24270             country: "GB"
24271           },
24272           geometry: null
24273         }, {
24274           type: "Feature",
24275           properties: {
24276             iso1A2: "GH",
24277             iso1A3: "GHA",
24278             iso1N3: "288",
24279             wikidata: "Q117",
24280             nameEn: "Ghana",
24281             groups: ["011", "202", "002", "UN"],
24282             callingCodes: ["233"]
24283           },
24284           geometry: {
24285             type: "MultiPolygon",
24286             coordinates: [[[[-0.13493, 11.14075], [-0.27374, 11.17157], [-0.28566, 11.12713], [-0.35955, 11.07801], [-0.38219, 11.12596], [-0.42391, 11.11661], [-0.44298, 11.04292], [-0.61937, 10.91305], [-0.67143, 10.99811], [-2.83373, 11.0067], [-2.94232, 10.64281], [-2.83108, 10.40252], [-2.74174, 9.83172], [-2.76534, 9.56589], [-2.68802, 9.49343], [-2.69814, 9.22717], [-2.77799, 9.04949], [-2.66357, 9.01771], [-2.58243, 8.7789], [-2.49037, 8.20872], [-2.62901, 8.11495], [-2.61232, 8.02645], [-2.67787, 8.02055], [-2.74819, 7.92613], [-2.78395, 7.94974], [-2.79467, 7.86002], [-2.92339, 7.60847], [-2.97822, 7.27165], [-2.95438, 7.23737], [-3.23327, 6.81744], [-3.21954, 6.74407], [-3.25999, 6.62521], [-3.01896, 5.71697], [-2.95323, 5.71865], [-2.96671, 5.6415], [-2.93132, 5.62137], [-2.85378, 5.65156], [-2.76614, 5.60963], [-2.72737, 5.34789], [-2.77625, 5.34621], [-2.73074, 5.1364], [-2.75502, 5.10657], [-2.95261, 5.12477], [-2.96554, 5.10397], [-3.063, 5.13665], [-3.11073, 5.12675], [-3.10675, 5.08515], [-3.34019, 4.17519], [1.07031, 5.15655], [1.27574, 5.93551], [1.19771, 6.11522], [1.19966, 6.17069], [1.09187, 6.17074], [1.05969, 6.22998], [1.03108, 6.24064], [0.99652, 6.33779], [0.89283, 6.33779], [0.71048, 6.53083], [0.74862, 6.56517], [0.63659, 6.63857], [0.6497, 6.73682], [0.58176, 6.76049], [0.57406, 6.80348], [0.52853, 6.82921], [0.56508, 6.92971], [0.52098, 6.94391], [0.52217, 6.9723], [0.59606, 7.01252], [0.65327, 7.31643], [0.62943, 7.41099], [0.57223, 7.39326], [0.52455, 7.45354], [0.51979, 7.58706], [0.58295, 7.62368], [0.62943, 7.85751], [0.58891, 8.12779], [0.6056, 8.13959], [0.61156, 8.18324], [0.5913, 8.19622], [0.63897, 8.25873], [0.73432, 8.29529], [0.64731, 8.48866], [0.47211, 8.59945], [0.37319, 8.75262], [0.52455, 8.87746], [0.45424, 9.04581], [0.56388, 9.40697], [0.49118, 9.48339], [0.36485, 9.49749], [0.33148, 9.44812], [0.25758, 9.42696], [0.2254, 9.47869], [0.31241, 9.50337], [0.30406, 9.521], [0.2409, 9.52335], [0.23851, 9.57389], [0.38153, 9.58682], [0.36008, 9.6256], [0.29334, 9.59387], [0.26712, 9.66437], [0.28261, 9.69022], [0.32313, 9.6491], [0.34816, 9.66907], [0.34816, 9.71607], [0.32075, 9.72781], [0.36366, 10.03309], [0.41252, 10.02018], [0.41371, 10.06361], [0.35293, 10.09412], [0.39584, 10.31112], [0.33028, 10.30408], [0.29453, 10.41546], [0.18846, 10.4096], [0.12886, 10.53149], [-0.05945, 10.63458], [-0.09141, 10.7147], [-0.07327, 10.71845], [-0.07183, 10.76794], [-0.0228, 10.81916], [-0.02685, 10.8783], [-908e-5, 10.91644], [-63e-4, 10.96417], [0.03355, 10.9807], [0.02395, 11.06229], [342e-5, 11.08317], [-514e-5, 11.10763], [-0.0275, 11.11202], [-0.05733, 11.08628], [-0.14462, 11.10811], [-0.13493, 11.14075]]]]
24287           }
24288         }, {
24289           type: "Feature",
24290           properties: {
24291             iso1A2: "GI",
24292             iso1A3: "GIB",
24293             iso1N3: "292",
24294             wikidata: "Q1410",
24295             nameEn: "Gibraltar",
24296             country: "GB",
24297             groups: ["Q12837", "BOTS", "039", "150", "UN"],
24298             callingCodes: ["350"]
24299           },
24300           geometry: {
24301             type: "MultiPolygon",
24302             coordinates: [[[[-5.34064, 36.03744], [-5.27801, 36.14942], [-5.33822, 36.15272], [-5.34536, 36.15501], [-5.40526, 36.15488], [-5.34064, 36.03744]]]]
24303           }
24304         }, {
24305           type: "Feature",
24306           properties: {
24307             iso1A2: "GL",
24308             iso1A3: "GRL",
24309             iso1N3: "304",
24310             wikidata: "Q223",
24311             nameEn: "Greenland",
24312             country: "DK",
24313             groups: ["Q1451600", "021", "003", "019", "UN"],
24314             callingCodes: ["299"]
24315           },
24316           geometry: {
24317             type: "MultiPolygon",
24318             coordinates: [[[[-49.33696, 84.57952], [-68.21821, 80.48551], [-77.52957, 77.23408], [-46.37635, 57.3249], [-9.68082, 72.73731], [-5.7106, 84.28058], [-49.33696, 84.57952]]]]
24319           }
24320         }, {
24321           type: "Feature",
24322           properties: {
24323             iso1A2: "GM",
24324             iso1A3: "GMB",
24325             iso1N3: "270",
24326             wikidata: "Q1005",
24327             nameEn: "The Gambia",
24328             groups: ["011", "202", "002", "UN"],
24329             callingCodes: ["220"]
24330           },
24331           geometry: {
24332             type: "MultiPolygon",
24333             coordinates: [[[[-15.14917, 13.57989], [-14.36795, 13.23033], [-13.79409, 13.34472], [-13.8955, 13.59126], [-14.34721, 13.46578], [-14.93719, 13.80173], [-15.36504, 13.79313], [-15.47902, 13.58758], [-17.43598, 13.59273], [-17.43966, 13.04579], [-16.74676, 13.06025], [-16.69343, 13.16791], [-15.80355, 13.16729], [-15.80478, 13.34832], [-15.26908, 13.37768], [-15.14917, 13.57989]]]]
24334           }
24335         }, {
24336           type: "Feature",
24337           properties: {
24338             iso1A2: "GN",
24339             iso1A3: "GIN",
24340             iso1N3: "324",
24341             wikidata: "Q1006",
24342             nameEn: "Guinea",
24343             groups: ["011", "202", "002", "UN"],
24344             callingCodes: ["224"]
24345           },
24346           geometry: {
24347             type: "MultiPolygon",
24348             coordinates: [[[[-11.37536, 12.40788], [-11.46267, 12.44559], [-11.91331, 12.42008], [-12.35415, 12.32758], [-12.87336, 12.51892], [-13.06603, 12.49342], [-13.05296, 12.64003], [-13.70523, 12.68013], [-13.7039, 12.60313], [-13.65089, 12.49515], [-13.64168, 12.42764], [-13.70851, 12.24978], [-13.92745, 12.24077], [-13.94589, 12.16869], [-13.7039, 12.00869], [-13.7039, 11.70195], [-14.09799, 11.63649], [-14.26623, 11.67486], [-14.31513, 11.60713], [-14.51173, 11.49708], [-14.66677, 11.51188], [-14.77786, 11.36323], [-14.95993, 10.99244], [-15.07174, 10.89557], [-15.96748, 10.162], [-14.36218, 8.64107], [-13.29911, 9.04245], [-13.18586, 9.0925], [-13.08953, 9.0409], [-12.94095, 9.26335], [-12.76788, 9.3133], [-12.47254, 9.86834], [-12.24262, 9.92386], [-12.12634, 9.87203], [-11.91023, 9.93927], [-11.89624, 9.99763], [-11.2118, 10.00098], [-10.6534, 9.29919], [-10.74484, 9.07998], [-10.5783, 9.06386], [-10.56197, 8.81225], [-10.47707, 8.67669], [-10.61422, 8.5314], [-10.70565, 8.29235], [-10.63934, 8.35326], [-10.54891, 8.31174], [-10.37257, 8.48941], [-10.27575, 8.48711], [-10.203, 8.47991], [-10.14579, 8.52665], [-10.05375, 8.50697], [-10.05873, 8.42578], [-9.77763, 8.54633], [-9.47415, 8.35195], [-9.50898, 8.18455], [-9.41445, 8.02448], [-9.44928, 7.9284], [-9.35724, 7.74111], [-9.37465, 7.62032], [-9.48161, 7.37122], [-9.41943, 7.41809], [-9.305, 7.42056], [-9.20798, 7.38109], [-9.18311, 7.30461], [-9.09107, 7.1985], [-8.93435, 7.2824], [-8.85724, 7.26019], [-8.8448, 7.35149], [-8.72789, 7.51429], [-8.67814, 7.69428], [-8.55874, 7.70167], [-8.55874, 7.62525], [-8.47114, 7.55676], [-8.4003, 7.6285], [-8.21374, 7.54466], [-8.09931, 7.78626], [-8.13414, 7.87991], [-8.06449, 8.04989], [-7.94695, 8.00925], [-7.99919, 8.11023], [-7.98675, 8.20134], [-8.062, 8.16071], [-8.2411, 8.24196], [-8.22991, 8.48438], [-7.92518, 8.50652], [-7.65653, 8.36873], [-7.69882, 8.66148], [-7.95503, 8.81146], [-7.92518, 8.99332], [-7.73862, 9.08422], [-7.90777, 9.20456], [-7.85056, 9.41812], [-8.03463, 9.39604], [-8.14657, 9.55062], [-8.09434, 9.86936], [-8.15652, 9.94288], [-8.11921, 10.04577], [-8.01225, 10.1021], [-7.97971, 10.17117], [-7.9578, 10.2703], [-8.10207, 10.44649], [-8.22711, 10.41722], [-8.32614, 10.69273], [-8.2667, 10.91762], [-8.35083, 11.06234], [-8.66923, 10.99397], [-8.40058, 11.37466], [-8.80854, 11.66715], [-8.94784, 12.34842], [-9.13689, 12.50875], [-9.38067, 12.48446], [-9.32097, 12.29009], [-9.63938, 12.18312], [-9.714, 12.0226], [-10.30604, 12.24634], [-10.71897, 11.91552], [-10.80355, 12.1053], [-10.99758, 12.24634], [-11.24136, 12.01286], [-11.50006, 12.17826], [-11.37536, 12.40788]]]]
24349           }
24350         }, {
24351           type: "Feature",
24352           properties: {
24353             iso1A2: "GP",
24354             iso1A3: "GLP",
24355             iso1N3: "312",
24356             wikidata: "Q17012",
24357             nameEn: "Guadeloupe",
24358             country: "FR",
24359             groups: ["Q3320166", "EU", "029", "003", "419", "019", "UN"],
24360             callingCodes: ["590"]
24361           },
24362           geometry: {
24363             type: "MultiPolygon",
24364             coordinates: [[[[-60.03183, 16.1129], [-61.60296, 16.73066], [-63.00549, 15.26166], [-60.03183, 16.1129]]]]
24365           }
24366         }, {
24367           type: "Feature",
24368           properties: {
24369             iso1A2: "GQ",
24370             iso1A3: "GNQ",
24371             iso1N3: "226",
24372             wikidata: "Q983",
24373             nameEn: "Equatorial Guinea",
24374             groups: ["017", "202", "002", "UN"],
24375             callingCodes: ["240"]
24376           },
24377           geometry: {
24378             type: "MultiPolygon",
24379             coordinates: [[[[9.22018, 3.72052], [8.34397, 4.30689], [7.71762, 0.6674], [3.35016, -3.29031], [9.66433, 1.06723], [9.75065, 1.06753], [9.79648, 1.0019], [11.35307, 1.00251], [11.3561, 2.17217], [9.991, 2.16561], [9.90749, 2.20049], [9.89012, 2.20457], [9.84716, 2.24676], [9.83238, 2.29079], [9.83754, 2.32428], [9.82123, 2.35097], [9.81162, 2.33797], [9.22018, 3.72052]]]]
24380           }
24381         }, {
24382           type: "Feature",
24383           properties: {
24384             iso1A2: "GR",
24385             iso1A3: "GRC",
24386             iso1N3: "300",
24387             wikidata: "Q41",
24388             nameEn: "Greece",
24389             aliases: ["EL"],
24390             groups: ["EU", "039", "150", "UN"],
24391             callingCodes: ["30"]
24392           },
24393           geometry: {
24394             type: "MultiPolygon",
24395             coordinates: [[[[26.03489, 40.73051], [26.0754, 40.72772], [26.08638, 40.73214], [26.12495, 40.74283], [26.12854, 40.77339], [26.15685, 40.80709], [26.21351, 40.83298], [26.20856, 40.86048], [26.26169, 40.9168], [26.29441, 40.89119], [26.28623, 40.93005], [26.32259, 40.94042], [26.35894, 40.94292], [26.33297, 40.98388], [26.3606, 41.02027], [26.31928, 41.07386], [26.32259, 41.24929], [26.39861, 41.25053], [26.5209, 41.33993], [26.5837, 41.32131], [26.62997, 41.34613], [26.61767, 41.42281], [26.59742, 41.48058], [26.59196, 41.60491], [26.5209, 41.62592], [26.47958, 41.67037], [26.35957, 41.71149], [26.30255, 41.70925], [26.2654, 41.71544], [26.22888, 41.74139], [26.21325, 41.73223], [26.16841, 41.74858], [26.06148, 41.70345], [26.07083, 41.64584], [26.15146, 41.60828], [26.14328, 41.55496], [26.17951, 41.55409], [26.176, 41.50072], [26.14796, 41.47533], [26.20288, 41.43943], [26.16548, 41.42278], [26.12926, 41.35878], [25.87919, 41.30526], [25.8266, 41.34563], [25.70507, 41.29209], [25.66183, 41.31316], [25.61042, 41.30614], [25.55082, 41.31667], [25.52394, 41.2798], [25.48187, 41.28506], [25.28322, 41.23411], [25.11611, 41.34212], [24.942, 41.38685], [24.90928, 41.40876], [24.86136, 41.39298], [24.82514, 41.4035], [24.8041, 41.34913], [24.71529, 41.41928], [24.61129, 41.42278], [24.52599, 41.56808], [24.30513, 41.51297], [24.27124, 41.57682], [24.18126, 41.51735], [24.10063, 41.54796], [24.06323, 41.53222], [24.06908, 41.46132], [23.96975, 41.44118], [23.91483, 41.47971], [23.89613, 41.45257], [23.80148, 41.43943], [23.76525, 41.40175], [23.67644, 41.41139], [23.63203, 41.37632], [23.52453, 41.40262], [23.40416, 41.39999], [23.33639, 41.36317], [23.31301, 41.40525], [23.22771, 41.37106], [23.21953, 41.33773], [23.1833, 41.31755], [22.93334, 41.34104], [22.81199, 41.3398], [22.76408, 41.32225], [22.74538, 41.16321], [22.71266, 41.13945], [22.65306, 41.18168], [22.62852, 41.14385], [22.58295, 41.11568], [22.5549, 41.13065], [22.42285, 41.11921], [22.26744, 41.16409], [22.17629, 41.15969], [22.1424, 41.12449], [22.06527, 41.15617], [21.90869, 41.09191], [21.91102, 41.04786], [21.7556, 40.92525], [21.69601, 40.9429], [21.57448, 40.86076], [21.53007, 40.90759], [21.41555, 40.9173], [21.35595, 40.87578], [21.25779, 40.86165], [21.21105, 40.8855], [21.15262, 40.85546], [20.97887, 40.85475], [20.98396, 40.79109], [20.95752, 40.76982], [20.98134, 40.76046], [21.05833, 40.66586], [21.03932, 40.56299], [20.96908, 40.51526], [20.94925, 40.46625], [20.83688, 40.47882], [20.7906, 40.42726], [20.78234, 40.35803], [20.71789, 40.27739], [20.67162, 40.09433], [20.62566, 40.0897], [20.61081, 40.07866], [20.55593, 40.06524], [20.51297, 40.08168], [20.48487, 40.06271], [20.42373, 40.06777], [20.37911, 39.99058], [20.31135, 39.99438], [20.41546, 39.82832], [20.41475, 39.81437], [20.38572, 39.78516], [20.30804, 39.81563], [20.29152, 39.80421], [20.31961, 39.72799], [20.27412, 39.69884], [20.22707, 39.67459], [20.22376, 39.64532], [20.15988, 39.652], [20.12956, 39.65805], [20.05189, 39.69112], [20.00957, 39.69227], [19.98042, 39.6504], [19.92466, 39.69533], [19.97622, 39.78684], [19.95905, 39.82857], [19.0384, 40.35325], [19.20409, 39.7532], [22.5213, 33.45682], [29.73302, 35.92555], [29.69611, 36.10365], [29.61805, 36.14179], [29.61002, 36.1731], [29.48192, 36.18377], [29.30783, 36.01033], [28.23708, 36.56812], [27.95037, 36.46155], [27.89482, 36.69898], [27.46117, 36.53789], [27.24613, 36.71622], [27.45627, 36.9008], [27.20312, 36.94571], [27.14757, 37.32], [26.95583, 37.64989], [26.99377, 37.69034], [27.16428, 37.72343], [27.05537, 37.9131], [26.21136, 38.17558], [26.24183, 38.44695], [26.32173, 38.48731], [26.21136, 38.65436], [26.61814, 38.81372], [26.70773, 39.0312], [26.43357, 39.43096], [25.94257, 39.39358], [25.61285, 40.17161], [26.04292, 40.3958], [25.94795, 40.72797], [26.03489, 40.73051]]]]
24396           }
24397         }, {
24398           type: "Feature",
24399           properties: {
24400             iso1A2: "GS",
24401             iso1A3: "SGS",
24402             iso1N3: "239",
24403             wikidata: "Q35086",
24404             nameEn: "South Georgia and South Sandwich Islands",
24405             country: "GB",
24406             groups: ["BOTS", "005", "419", "019", "UN"],
24407             driveSide: "left",
24408             roadSpeedUnit: "mph",
24409             roadHeightUnit: "ft",
24410             callingCodes: ["500"]
24411           },
24412           geometry: {
24413             type: "MultiPolygon",
24414             coordinates: [[[[-35.26394, -43.68272], [-53.39656, -59.87088], [-22.31757, -59.85974], [-35.26394, -43.68272]]]]
24415           }
24416         }, {
24417           type: "Feature",
24418           properties: {
24419             iso1A2: "GT",
24420             iso1A3: "GTM",
24421             iso1N3: "320",
24422             wikidata: "Q774",
24423             nameEn: "Guatemala",
24424             groups: ["013", "003", "419", "019", "UN"],
24425             callingCodes: ["502"]
24426           },
24427           geometry: {
24428             type: "MultiPolygon",
24429             coordinates: [[[[-89.14985, 17.81563], [-90.98678, 17.81655], [-90.99199, 17.25192], [-91.43809, 17.25373], [-91.04436, 16.92175], [-90.69064, 16.70697], [-90.61212, 16.49832], [-90.40499, 16.40524], [-90.44567, 16.07573], [-91.73182, 16.07371], [-92.20983, 15.26077], [-92.0621, 15.07406], [-92.1454, 14.98143], [-92.1423, 14.88647], [-92.18161, 14.84147], [-92.1454, 14.6804], [-92.2261, 14.53423], [-92.37213, 14.39277], [-90.55276, 12.8866], [-90.11344, 13.73679], [-90.10505, 13.85104], [-89.88937, 14.0396], [-89.81807, 14.07073], [-89.76103, 14.02923], [-89.73251, 14.04133], [-89.75569, 14.07073], [-89.70756, 14.1537], [-89.61844, 14.21937], [-89.52397, 14.22628], [-89.50614, 14.26084], [-89.58814, 14.33165], [-89.57441, 14.41637], [-89.39028, 14.44561], [-89.34776, 14.43013], [-89.35189, 14.47553], [-89.23719, 14.58046], [-89.15653, 14.57802], [-89.13132, 14.71582], [-89.23467, 14.85596], [-89.15149, 14.97775], [-89.18048, 14.99967], [-89.15149, 15.07392], [-88.97343, 15.14039], [-88.32467, 15.63665], [-88.31459, 15.66942], [-88.24022, 15.69247], [-88.22552, 15.72294], [-88.20359, 16.03858], [-88.40779, 16.09624], [-88.95358, 15.88698], [-89.02415, 15.9063], [-89.17418, 15.90898], [-89.22683, 15.88619], [-89.15025, 17.04813], [-89.14985, 17.81563]]]]
24430           }
24431         }, {
24432           type: "Feature",
24433           properties: {
24434             iso1A2: "GU",
24435             iso1A3: "GUM",
24436             iso1N3: "316",
24437             wikidata: "Q16635",
24438             nameEn: "Guam",
24439             aliases: ["US-GU"],
24440             country: "US",
24441             groups: ["Q1352230", "Q153732", "057", "009", "UN"],
24442             roadSpeedUnit: "mph",
24443             roadHeightUnit: "ft",
24444             callingCodes: ["1 671"]
24445           },
24446           geometry: {
24447             type: "MultiPolygon",
24448             coordinates: [[[[146.25931, 13.85876], [143.82485, 13.92273], [144.61642, 12.82462], [146.25931, 13.85876]]]]
24449           }
24450         }, {
24451           type: "Feature",
24452           properties: {
24453             iso1A2: "GW",
24454             iso1A3: "GNB",
24455             iso1N3: "624",
24456             wikidata: "Q1007",
24457             nameEn: "Guinea-Bissau",
24458             groups: ["011", "202", "002", "UN"],
24459             callingCodes: ["245"]
24460           },
24461           geometry: {
24462             type: "MultiPolygon",
24463             coordinates: [[[[-14.31513, 11.60713], [-14.26623, 11.67486], [-14.09799, 11.63649], [-13.7039, 11.70195], [-13.7039, 12.00869], [-13.94589, 12.16869], [-13.92745, 12.24077], [-13.70851, 12.24978], [-13.64168, 12.42764], [-13.65089, 12.49515], [-13.7039, 12.60313], [-13.70523, 12.68013], [-15.17582, 12.6847], [-15.67302, 12.42974], [-16.20591, 12.46157], [-16.38191, 12.36449], [-16.70562, 12.34803], [-17.4623, 11.92379], [-15.96748, 10.162], [-15.07174, 10.89557], [-14.95993, 10.99244], [-14.77786, 11.36323], [-14.66677, 11.51188], [-14.51173, 11.49708], [-14.31513, 11.60713]]]]
24464           }
24465         }, {
24466           type: "Feature",
24467           properties: {
24468             iso1A2: "GY",
24469             iso1A3: "GUY",
24470             iso1N3: "328",
24471             wikidata: "Q734",
24472             nameEn: "Guyana",
24473             groups: ["005", "419", "019", "UN"],
24474             driveSide: "left",
24475             callingCodes: ["592"]
24476           },
24477           geometry: {
24478             type: "MultiPolygon",
24479             coordinates: [[[[-56.84822, 6.73257], [-59.54058, 8.6862], [-59.98508, 8.53046], [-59.85562, 8.35213], [-59.80661, 8.28906], [-59.83156, 8.23261], [-59.97059, 8.20791], [-60.02407, 8.04557], [-60.38056, 7.8302], [-60.51959, 7.83373], [-60.64793, 7.56877], [-60.71923, 7.55817], [-60.59802, 7.33194], [-60.63367, 7.25061], [-60.54098, 7.14804], [-60.44116, 7.20817], [-60.28074, 7.1162], [-60.39419, 6.94847], [-60.54873, 6.8631], [-61.13632, 6.70922], [-61.20762, 6.58174], [-61.15058, 6.19558], [-61.4041, 5.95304], [-60.73204, 5.20931], [-60.32352, 5.21299], [-60.20944, 5.28754], [-59.98129, 5.07097], [-60.04189, 4.69801], [-60.15953, 4.53456], [-59.78878, 4.45637], [-59.69361, 4.34069], [-59.73353, 4.20399], [-59.51963, 3.91951], [-59.86899, 3.57089], [-59.79769, 3.37162], [-59.99733, 2.92312], [-59.91177, 2.36759], [-59.7264, 2.27497], [-59.74066, 1.87596], [-59.25583, 1.40559], [-58.92072, 1.31293], [-58.84229, 1.17749], [-58.53571, 1.29154], [-58.4858, 1.48399], [-58.33887, 1.58014], [-58.01873, 1.51966], [-57.97336, 1.64566], [-57.77281, 1.73344], [-57.55743, 1.69605], [-57.35073, 1.98327], [-57.23981, 1.95808], [-57.09109, 2.01854], [-57.07092, 1.95304], [-56.7659, 1.89509], [-56.47045, 1.95135], [-56.55439, 2.02003], [-56.70519, 2.02964], [-57.35891, 3.32121], [-58.0307, 3.95513], [-57.8699, 4.89394], [-57.37442, 5.0208], [-57.22536, 5.15605], [-57.31629, 5.33714], [-56.84822, 6.73257]]]]
24480           }
24481         }, {
24482           type: "Feature",
24483           properties: {
24484             iso1A2: "HK",
24485             iso1A3: "HKG",
24486             iso1N3: "344",
24487             wikidata: "Q8646",
24488             nameEn: "Hong Kong",
24489             country: "CN",
24490             groups: ["030", "142", "UN"],
24491             driveSide: "left",
24492             callingCodes: ["852"]
24493           },
24494           geometry: {
24495             type: "MultiPolygon",
24496             coordinates: [[[[113.92195, 22.13873], [114.50148, 22.15017], [114.44998, 22.55977], [114.25154, 22.55977], [114.22888, 22.5436], [114.22185, 22.55343], [114.20655, 22.55706], [114.18338, 22.55444], [114.17247, 22.55944], [114.1597, 22.56041], [114.15123, 22.55163], [114.1482, 22.54091], [114.13823, 22.54319], [114.12665, 22.54003], [114.11656, 22.53415], [114.11181, 22.52878], [114.1034, 22.5352], [114.09692, 22.53435], [114.09048, 22.53716], [114.08606, 22.53276], [114.07817, 22.52997], [114.07267, 22.51855], [114.06272, 22.51617], [114.05729, 22.51104], [114.05438, 22.5026], [114.03113, 22.5065], [113.86771, 22.42972], [113.81621, 22.2163], [113.83338, 22.1826], [113.92195, 22.13873]]]]
24497           }
24498         }, {
24499           type: "Feature",
24500           properties: {
24501             iso1A2: "HM",
24502             iso1A3: "HMD",
24503             iso1N3: "334",
24504             wikidata: "Q131198",
24505             nameEn: "Heard Island and McDonald Islands",
24506             country: "AU",
24507             groups: ["053", "009", "UN"],
24508             driveSide: "left"
24509           },
24510           geometry: {
24511             type: "MultiPolygon",
24512             coordinates: [[[[71.08716, -53.87687], [75.44182, -53.99822], [72.87012, -51.48322], [71.08716, -53.87687]]]]
24513           }
24514         }, {
24515           type: "Feature",
24516           properties: {
24517             iso1A2: "HN",
24518             iso1A3: "HND",
24519             iso1N3: "340",
24520             wikidata: "Q783",
24521             nameEn: "Honduras",
24522             groups: ["013", "003", "419", "019", "UN"],
24523             callingCodes: ["504"]
24524           },
24525           geometry: {
24526             type: "MultiPolygon",
24527             coordinates: [[[[-83.86109, 17.73736], [-88.20359, 16.03858], [-88.22552, 15.72294], [-88.24022, 15.69247], [-88.31459, 15.66942], [-88.32467, 15.63665], [-88.97343, 15.14039], [-89.15149, 15.07392], [-89.18048, 14.99967], [-89.15149, 14.97775], [-89.23467, 14.85596], [-89.13132, 14.71582], [-89.15653, 14.57802], [-89.23719, 14.58046], [-89.35189, 14.47553], [-89.34776, 14.43013], [-89.04187, 14.33644], [-88.94608, 14.20207], [-88.85785, 14.17763], [-88.815, 14.11652], [-88.73182, 14.10919], [-88.70661, 14.04317], [-88.49738, 13.97224], [-88.48982, 13.86458], [-88.25791, 13.91108], [-88.23018, 13.99915], [-88.07641, 13.98447], [-88.00331, 13.86948], [-87.7966, 13.91353], [-87.68821, 13.80829], [-87.73106, 13.75443], [-87.78148, 13.52906], [-87.71657, 13.50577], [-87.72115, 13.46083], [-87.73841, 13.44169], [-87.77354, 13.45767], [-87.83467, 13.44655], [-87.84675, 13.41078], [-87.80177, 13.35689], [-87.73714, 13.32715], [-87.69751, 13.25228], [-87.55124, 13.12523], [-87.37107, 12.98646], [-87.06306, 13.00892], [-87.03785, 12.98682], [-86.93197, 13.05313], [-86.93383, 13.18677], [-86.87066, 13.30641], [-86.71267, 13.30348], [-86.76812, 13.79605], [-86.35219, 13.77157], [-86.14801, 14.04317], [-86.00685, 14.08474], [-86.03458, 13.99181], [-85.75477, 13.8499], [-85.73964, 13.9698], [-85.45762, 14.11304], [-85.32149, 14.2562], [-85.18602, 14.24929], [-85.1575, 14.53934], [-84.90082, 14.80489], [-84.82596, 14.82212], [-84.70119, 14.68078], [-84.48373, 14.63249], [-84.10584, 14.76353], [-83.89551, 14.76697], [-83.62101, 14.89448], [-83.49268, 15.01158], [-83.13724, 15.00002], [-83.04763, 15.03256], [-82.06974, 14.49418], [-81.58685, 18.0025], [-83.86109, 17.73736]]]]
24528           }
24529         }, {
24530           type: "Feature",
24531           properties: {
24532             iso1A2: "HR",
24533             iso1A3: "HRV",
24534             iso1N3: "191",
24535             wikidata: "Q224",
24536             nameEn: "Croatia",
24537             groups: ["EU", "039", "150", "UN"],
24538             callingCodes: ["385"]
24539           },
24540           geometry: {
24541             type: "MultiPolygon",
24542             coordinates: [[[[17.6444, 42.88641], [17.5392, 42.92787], [17.70879, 42.97223], [17.64268, 43.08595], [17.46986, 43.16559], [17.286, 43.33065], [17.25579, 43.40353], [17.29699, 43.44542], [17.24411, 43.49376], [17.15828, 43.49376], [17.00585, 43.58037], [16.80736, 43.76011], [16.75316, 43.77157], [16.70922, 43.84887], [16.55472, 43.95326], [16.50528, 44.0244], [16.43629, 44.02826], [16.43662, 44.07523], [16.36864, 44.08263], [16.18688, 44.27012], [16.21346, 44.35231], [16.12969, 44.38275], [16.16814, 44.40679], [16.10566, 44.52586], [16.03012, 44.55572], [16.00884, 44.58605], [16.05828, 44.61538], [15.89348, 44.74964], [15.8255, 44.71501], [15.72584, 44.82334], [15.79472, 44.8455], [15.76096, 44.87045], [15.74723, 44.96818], [15.78568, 44.97401], [15.74585, 45.0638], [15.78842, 45.11519], [15.76371, 45.16508], [15.83512, 45.22459], [15.98412, 45.23088], [16.12153, 45.09616], [16.29036, 44.99732], [16.35404, 45.00241], [16.35863, 45.03529], [16.3749, 45.05206], [16.38219, 45.05139], [16.38309, 45.05955], [16.40023, 45.1147], [16.4634, 45.14522], [16.49155, 45.21153], [16.52982, 45.22713], [16.5501, 45.2212], [16.56559, 45.22307], [16.60194, 45.23042], [16.64962, 45.20714], [16.74845, 45.20393], [16.78219, 45.19002], [16.81137, 45.18434], [16.83804, 45.18951], [16.92405, 45.27607], [16.9385, 45.22742], [17.0415, 45.20759], [17.18438, 45.14764], [17.24325, 45.146], [17.25131, 45.14957], [17.26815, 45.18444], [17.32092, 45.16246], [17.33573, 45.14521], [17.41229, 45.13335], [17.4498, 45.16119], [17.45615, 45.12523], [17.47589, 45.12656], [17.51469, 45.10791], [17.59104, 45.10816], [17.66571, 45.13408], [17.84826, 45.04489], [17.87148, 45.04645], [17.93706, 45.08016], [17.97336, 45.12245], [17.97834, 45.13831], [17.99479, 45.14958], [18.01594, 45.15163], [18.03121, 45.12632], [18.1624, 45.07654], [18.24387, 45.13699], [18.32077, 45.1021], [18.41896, 45.11083], [18.47939, 45.05871], [18.65723, 45.07544], [18.78357, 44.97741], [18.80661, 44.93561], [18.76369, 44.93707], [18.76347, 44.90669], [18.8704, 44.85097], [19.01994, 44.85493], [18.98957, 44.90645], [19.02871, 44.92541], [19.06853, 44.89915], [19.15573, 44.95409], [19.05205, 44.97692], [19.1011, 45.01191], [19.07952, 45.14668], [19.14063, 45.12972], [19.19144, 45.17863], [19.43589, 45.17137], [19.41941, 45.23475], [19.28208, 45.23813], [19.10774, 45.29547], [18.97446, 45.37528], [18.99918, 45.49333], [19.08364, 45.48804], [19.07471, 45.53086], [18.94562, 45.53712], [18.88776, 45.57253], [18.96691, 45.66731], [18.90305, 45.71863], [18.85783, 45.85493], [18.81394, 45.91329], [18.80211, 45.87995], [18.6792, 45.92057], [18.57483, 45.80772], [18.44368, 45.73972], [18.12439, 45.78905], [18.08869, 45.76511], [17.99805, 45.79671], [17.87377, 45.78522], [17.66545, 45.84207], [17.56821, 45.93728], [17.35672, 45.95209], [17.14592, 46.16697], [16.8903, 46.28122], [16.8541, 46.36255], [16.7154, 46.39523], [16.6639, 46.45203], [16.59527, 46.47524], [16.52604, 46.47831], [16.5007, 46.49644], [16.44036, 46.5171], [16.38771, 46.53608], [16.37193, 46.55008], [16.29793, 46.5121], [16.26733, 46.51505], [16.26759, 46.50566], [16.23961, 46.49653], [16.25124, 46.48067], [16.27398, 46.42875], [16.27329, 46.41467], [16.30162, 46.40437], [16.30233, 46.37837], [16.18824, 46.38282], [16.14859, 46.40547], [16.05281, 46.39141], [16.05065, 46.3833], [16.07314, 46.36458], [16.07616, 46.3463], [15.97965, 46.30652], [15.79284, 46.25811], [15.78817, 46.21719], [15.75479, 46.20336], [15.75436, 46.21969], [15.67395, 46.22478], [15.6434, 46.21396], [15.64904, 46.19229], [15.59909, 46.14761], [15.6083, 46.11992], [15.62317, 46.09103], [15.72977, 46.04682], [15.71246, 46.01196], [15.70327, 46.00015], [15.70636, 45.92116], [15.67967, 45.90455], [15.68383, 45.88867], [15.68232, 45.86819], [15.70411, 45.8465], [15.66662, 45.84085], [15.64185, 45.82915], [15.57952, 45.84953], [15.52234, 45.82195], [15.47325, 45.8253], [15.47531, 45.79802], [15.40836, 45.79491], [15.25423, 45.72275], [15.30872, 45.69014], [15.34919, 45.71623], [15.4057, 45.64727], [15.38952, 45.63682], [15.34214, 45.64702], [15.34695, 45.63382], [15.31027, 45.6303], [15.27747, 45.60504], [15.29837, 45.5841], [15.30249, 45.53224], [15.38188, 45.48752], [15.33051, 45.45258], [15.27758, 45.46678], [15.16862, 45.42309], [15.05187, 45.49079], [15.02385, 45.48533], [14.92266, 45.52788], [14.90554, 45.47769], [14.81992, 45.45913], [14.80124, 45.49515], [14.71718, 45.53442], [14.68605, 45.53006], [14.69694, 45.57366], [14.59576, 45.62812], [14.60977, 45.66403], [14.57397, 45.67165], [14.53816, 45.6205], [14.5008, 45.60852], [14.49769, 45.54424], [14.36693, 45.48642], [14.32487, 45.47142], [14.27681, 45.4902], [14.26611, 45.48239], [14.24239, 45.50607], [14.22371, 45.50388], [14.20348, 45.46896], [14.07116, 45.48752], [14.00578, 45.52352], [13.96063, 45.50825], [13.99488, 45.47551], [13.97309, 45.45258], [13.90771, 45.45149], [13.88124, 45.42637], [13.81742, 45.43729], [13.7785, 45.46787], [13.67398, 45.4436], [13.62902, 45.45898], [13.56979, 45.4895], [13.45644, 45.59464], [13.05142, 45.33128], [13.12821, 44.48877], [16.15283, 42.18525], [18.45131, 42.21682], [18.54128, 42.39171], [18.52152, 42.42302], [18.43588, 42.48556], [18.44307, 42.51077], [18.43735, 42.55921], [18.36197, 42.61423], [18.24318, 42.6112], [17.88201, 42.83668], [17.80854, 42.9182], [17.7948, 42.89556], [17.68151, 42.92725], [17.6444, 42.88641]]]]
24543           }
24544         }, {
24545           type: "Feature",
24546           properties: {
24547             iso1A2: "HT",
24548             iso1A3: "HTI",
24549             iso1N3: "332",
24550             wikidata: "Q790",
24551             nameEn: "Haiti",
24552             aliases: ["RH"],
24553             groups: ["029", "003", "419", "019", "UN"],
24554             callingCodes: ["509"]
24555           },
24556           geometry: {
24557             type: "MultiPolygon",
24558             coordinates: [[[[-71.71885, 18.78423], [-71.72624, 18.87802], [-71.77766, 18.95007], [-71.88102, 18.95007], [-71.74088, 19.0437], [-71.71088, 19.08353], [-71.69938, 19.10916], [-71.65337, 19.11759], [-71.62642, 19.21212], [-71.73229, 19.26686], [-71.77766, 19.33823], [-71.69448, 19.37866], [-71.6802, 19.45008], [-71.71268, 19.53374], [-71.71449, 19.55364], [-71.7429, 19.58445], [-71.75865, 19.70231], [-71.77419, 19.73128], [-72.38946, 20.27111], [-73.37289, 20.43199], [-74.7289, 18.71009], [-74.76465, 18.06252], [-72.29523, 17.48026], [-71.75671, 18.03456], [-71.73783, 18.07177], [-71.74994, 18.11115], [-71.75465, 18.14405], [-71.78271, 18.18302], [-71.69952, 18.34101], [-71.90875, 18.45821], [-71.88102, 18.50125], [-72.00201, 18.62312], [-71.95412, 18.64939], [-71.82556, 18.62551], [-71.71885, 18.78423]]]]
24559           }
24560         }, {
24561           type: "Feature",
24562           properties: {
24563             iso1A2: "HU",
24564             iso1A3: "HUN",
24565             iso1N3: "348",
24566             wikidata: "Q28",
24567             nameEn: "Hungary",
24568             groups: ["EU", "151", "150", "UN"],
24569             callingCodes: ["36"]
24570           },
24571           geometry: {
24572             type: "MultiPolygon",
24573             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]]]]
24574           }
24575         }, {
24576           type: "Feature",
24577           properties: {
24578             iso1A2: "IC",
24579             wikidata: "Q5813",
24580             nameEn: "Canary Islands",
24581             country: "ES",
24582             groups: ["Q3320166", "Q105472", "EU", "039", "150", "UN"],
24583             isoStatus: "excRes",
24584             callingCodes: ["34"]
24585           },
24586           geometry: {
24587             type: "MultiPolygon",
24588             coordinates: [[[[-12.00985, 30.24121], [-25.3475, 27.87574], [-14.43883, 27.02969], [-12.00985, 30.24121]]]]
24589           }
24590         }, {
24591           type: "Feature",
24592           properties: {
24593             iso1A2: "ID",
24594             iso1A3: "IDN",
24595             iso1N3: "360",
24596             wikidata: "Q252",
24597             nameEn: "Indonesia",
24598             aliases: ["RI"]
24599           },
24600           geometry: null
24601         }, {
24602           type: "Feature",
24603           properties: {
24604             iso1A2: "IE",
24605             iso1A3: "IRL",
24606             iso1N3: "372",
24607             wikidata: "Q27",
24608             nameEn: "Republic of Ireland",
24609             groups: ["EU", "Q22890", "154", "150", "UN"],
24610             driveSide: "left",
24611             callingCodes: ["353"]
24612           },
24613           geometry: {
24614             type: "MultiPolygon",
24615             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]]]]
24616           }
24617         }, {
24618           type: "Feature",
24619           properties: {
24620             iso1A2: "IL",
24621             iso1A3: "ISR",
24622             iso1N3: "376",
24623             wikidata: "Q801",
24624             nameEn: "Israel",
24625             groups: ["145", "142", "UN"],
24626             callingCodes: ["972"]
24627           },
24628           geometry: {
24629             type: "MultiPolygon",
24630             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]]]]
24631           }
24632         }, {
24633           type: "Feature",
24634           properties: {
24635             iso1A2: "IM",
24636             iso1A3: "IMN",
24637             iso1N3: "833",
24638             wikidata: "Q9676",
24639             nameEn: "Isle of Man",
24640             country: "GB",
24641             groups: ["Q185086", "154", "150", "UN"],
24642             driveSide: "left",
24643             roadSpeedUnit: "mph",
24644             roadHeightUnit: "ft",
24645             callingCodes: ["44 01624", "44 07624", "44 07524", "44 07924"]
24646           },
24647           geometry: {
24648             type: "MultiPolygon",
24649             coordinates: [[[[-3.98763, 54.07351], [-4.1819, 54.57861], [-5.6384, 53.81157], [-3.98763, 54.07351]]]]
24650           }
24651         }, {
24652           type: "Feature",
24653           properties: {
24654             iso1A2: "IN",
24655             iso1A3: "IND",
24656             iso1N3: "356",
24657             wikidata: "Q668",
24658             nameEn: "India"
24659           },
24660           geometry: null
24661         }, {
24662           type: "Feature",
24663           properties: {
24664             iso1A2: "IO",
24665             iso1A3: "IOT",
24666             iso1N3: "086",
24667             wikidata: "Q43448",
24668             nameEn: "British Indian Ocean Territory",
24669             country: "GB"
24670           },
24671           geometry: null
24672         }, {
24673           type: "Feature",
24674           properties: {
24675             iso1A2: "IQ",
24676             iso1A3: "IRQ",
24677             iso1N3: "368",
24678             wikidata: "Q796",
24679             nameEn: "Iraq",
24680             groups: ["145", "142", "UN"],
24681             callingCodes: ["964"]
24682           },
24683           geometry: {
24684             type: "MultiPolygon",
24685             coordinates: [[[[42.78887, 37.38615], [42.56725, 37.14878], [42.35724, 37.10998], [42.36697, 37.0627], [41.81736, 36.58782], [41.40058, 36.52502], [41.28864, 36.35368], [41.2564, 36.06012], [41.37027, 35.84095], [41.38184, 35.62502], [41.26569, 35.42708], [41.21654, 35.1508], [41.2345, 34.80049], [41.12388, 34.65742], [40.97676, 34.39788], [40.64314, 34.31604], [38.79171, 33.37328], [39.08202, 32.50304], [38.98762, 32.47694], [39.04251, 32.30203], [39.26157, 32.35555], [39.29903, 32.23259], [40.01521, 32.05667], [42.97601, 30.72204], [42.97796, 30.48295], [44.72255, 29.19736], [46.42415, 29.05947], [46.5527, 29.10283], [46.89695, 29.50584], [47.15166, 30.01044], [47.37192, 30.10421], [47.7095, 30.10453], [48.01114, 29.98906], [48.06782, 30.02906], [48.17332, 30.02448], [48.40479, 29.85763], [48.59531, 29.66815], [48.83867, 29.78572], [48.61441, 29.93675], [48.51011, 29.96238], [48.44785, 30.00148], [48.4494, 30.04456], [48.43384, 30.08233], [48.38869, 30.11062], [48.38714, 30.13485], [48.41671, 30.17254], [48.41117, 30.19846], [48.26393, 30.3408], [48.24385, 30.33846], [48.21279, 30.31644], [48.19425, 30.32796], [48.18321, 30.39703], [48.14585, 30.44133], [48.02443, 30.4789], [48.03221, 30.9967], [47.68219, 31.00004], [47.6804, 31.39086], [47.86337, 31.78422], [47.64771, 32.07666], [47.52474, 32.15972], [47.57144, 32.20583], [47.37529, 32.47808], [47.17218, 32.45393], [46.46788, 32.91992], [46.32298, 32.9731], [46.17198, 32.95612], [46.09103, 32.98354], [46.15175, 33.07229], [46.03966, 33.09577], [46.05367, 33.13097], [46.11905, 33.11924], [46.20623, 33.20395], [45.99919, 33.5082], [45.86687, 33.49263], [45.96183, 33.55751], [45.89801, 33.63661], [45.77814, 33.60938], [45.50261, 33.94968], [45.42789, 33.9458], [45.41077, 33.97421], [45.47264, 34.03099], [45.56176, 34.15088], [45.58667, 34.30147], [45.53552, 34.35148], [45.49171, 34.3439], [45.46697, 34.38221], [45.43879, 34.45949], [45.51883, 34.47692], [45.53219, 34.60441], [45.59074, 34.55558], [45.60224, 34.55057], [45.73923, 34.54416], [45.70031, 34.69277], [45.65672, 34.7222], [45.68284, 34.76624], [45.70031, 34.82322], [45.73641, 34.83975], [45.79682, 34.85133], [45.78904, 34.91135], [45.86532, 34.89858], [45.89477, 34.95805], [45.87864, 35.03441], [45.92173, 35.0465], [45.92203, 35.09538], [45.93108, 35.08148], [45.94756, 35.09188], [46.06508, 35.03699], [46.07747, 35.0838], [46.11763, 35.07551], [46.19116, 35.11097], [46.15642, 35.1268], [46.16229, 35.16984], [46.19738, 35.18536], [46.18457, 35.22561], [46.11367, 35.23729], [46.15474, 35.2883], [46.13152, 35.32548], [46.05358, 35.38568], [45.98453, 35.49848], [46.01518, 35.52012], [45.97584, 35.58132], [46.03028, 35.57416], [46.01307, 35.59756], [46.0165, 35.61501], [45.99452, 35.63574], [46.0117, 35.65059], [46.01631, 35.69139], [46.23736, 35.71414], [46.34166, 35.78363], [46.32921, 35.82655], [46.17198, 35.8013], [46.08325, 35.8581], [45.94711, 35.82218], [45.89784, 35.83708], [45.81442, 35.82107], [45.76145, 35.79898], [45.6645, 35.92872], [45.60018, 35.96069], [45.55245, 35.99943], [45.46594, 36.00042], [45.38275, 35.97156], [45.33916, 35.99424], [45.37652, 36.06222], [45.37312, 36.09917], [45.32235, 36.17383], [45.30038, 36.27769], [45.26261, 36.3001], [45.27394, 36.35846], [45.23953, 36.43257], [45.11811, 36.40751], [45.00759, 36.5402], [45.06985, 36.62645], [45.06985, 36.6814], [45.01537, 36.75128], [44.84725, 36.77622], [44.83479, 36.81362], [44.90173, 36.86096], [44.91199, 36.91468], [44.89862, 37.01897], [44.81611, 37.04383], [44.75229, 37.11958], [44.78319, 37.1431], [44.76698, 37.16162], [44.63179, 37.19229], [44.42631, 37.05825], [44.38117, 37.05825], [44.35315, 37.04955], [44.35937, 37.02843], [44.30645, 36.97373], [44.25975, 36.98119], [44.18503, 37.09551], [44.22239, 37.15756], [44.27998, 37.16501], [44.2613, 37.25055], [44.13521, 37.32486], [44.02002, 37.33229], [43.90949, 37.22453], [43.84878, 37.22205], [43.82699, 37.19477], [43.8052, 37.22825], [43.7009, 37.23692], [43.63085, 37.21957], [43.56702, 37.25675], [43.50787, 37.24436], [43.33508, 37.33105], [43.30083, 37.30629], [43.11403, 37.37436], [42.93705, 37.32015], [42.78887, 37.38615]]]]
24686           }
24687         }, {
24688           type: "Feature",
24689           properties: {
24690             iso1A2: "IR",
24691             iso1A3: "IRN",
24692             iso1N3: "364",
24693             wikidata: "Q794",
24694             nameEn: "Iran",
24695             groups: ["034", "142", "UN"],
24696             callingCodes: ["98"]
24697           },
24698           geometry: {
24699             type: "MultiPolygon",
24700             coordinates: [[[[44.96746, 39.42998], [44.88916, 39.59653], [44.81043, 39.62677], [44.71806, 39.71124], [44.65422, 39.72163], [44.6137, 39.78393], [44.47298, 39.68788], [44.48111, 39.61579], [44.41849, 39.56659], [44.42832, 39.4131], [44.37921, 39.4131], [44.29818, 39.378], [44.22452, 39.4169], [44.03667, 39.39223], [44.1043, 39.19842], [44.20946, 39.13975], [44.18863, 38.93881], [44.30322, 38.81581], [44.26155, 38.71427], [44.28065, 38.6465], [44.32058, 38.62752], [44.3207, 38.49799], [44.3119, 38.37887], [44.38309, 38.36117], [44.44386, 38.38295], [44.50115, 38.33939], [44.42476, 38.25763], [44.22509, 37.88859], [44.3883, 37.85433], [44.45948, 37.77065], [44.55498, 37.783], [44.62096, 37.71985], [44.56887, 37.6429], [44.61401, 37.60165], [44.58449, 37.45018], [44.81021, 37.2915], [44.75986, 37.21549], [44.7868, 37.16644], [44.78319, 37.1431], [44.75229, 37.11958], [44.81611, 37.04383], [44.89862, 37.01897], [44.91199, 36.91468], [44.90173, 36.86096], [44.83479, 36.81362], [44.84725, 36.77622], [45.01537, 36.75128], [45.06985, 36.6814], [45.06985, 36.62645], [45.00759, 36.5402], [45.11811, 36.40751], [45.23953, 36.43257], [45.27394, 36.35846], [45.26261, 36.3001], [45.30038, 36.27769], [45.32235, 36.17383], [45.37312, 36.09917], [45.37652, 36.06222], [45.33916, 35.99424], [45.38275, 35.97156], [45.46594, 36.00042], [45.55245, 35.99943], [45.60018, 35.96069], [45.6645, 35.92872], [45.76145, 35.79898], [45.81442, 35.82107], [45.89784, 35.83708], [45.94711, 35.82218], [46.08325, 35.8581], [46.17198, 35.8013], [46.32921, 35.82655], [46.34166, 35.78363], [46.23736, 35.71414], [46.01631, 35.69139], [46.0117, 35.65059], [45.99452, 35.63574], [46.0165, 35.61501], [46.01307, 35.59756], [46.03028, 35.57416], [45.97584, 35.58132], [46.01518, 35.52012], [45.98453, 35.49848], [46.05358, 35.38568], [46.13152, 35.32548], [46.15474, 35.2883], [46.11367, 35.23729], [46.18457, 35.22561], [46.19738, 35.18536], [46.16229, 35.16984], [46.15642, 35.1268], [46.19116, 35.11097], [46.11763, 35.07551], [46.07747, 35.0838], [46.06508, 35.03699], [45.94756, 35.09188], [45.93108, 35.08148], [45.92203, 35.09538], [45.92173, 35.0465], [45.87864, 35.03441], [45.89477, 34.95805], [45.86532, 34.89858], [45.78904, 34.91135], [45.79682, 34.85133], [45.73641, 34.83975], [45.70031, 34.82322], [45.68284, 34.76624], [45.65672, 34.7222], [45.70031, 34.69277], [45.73923, 34.54416], [45.60224, 34.55057], [45.59074, 34.55558], [45.53219, 34.60441], [45.51883, 34.47692], [45.43879, 34.45949], [45.46697, 34.38221], [45.49171, 34.3439], [45.53552, 34.35148], [45.58667, 34.30147], [45.56176, 34.15088], [45.47264, 34.03099], [45.41077, 33.97421], [45.42789, 33.9458], [45.50261, 33.94968], [45.77814, 33.60938], [45.89801, 33.63661], [45.96183, 33.55751], [45.86687, 33.49263], [45.99919, 33.5082], [46.20623, 33.20395], [46.11905, 33.11924], [46.05367, 33.13097], [46.03966, 33.09577], [46.15175, 33.07229], [46.09103, 32.98354], [46.17198, 32.95612], [46.32298, 32.9731], [46.46788, 32.91992], [47.17218, 32.45393], [47.37529, 32.47808], [47.57144, 32.20583], [47.52474, 32.15972], [47.64771, 32.07666], [47.86337, 31.78422], [47.6804, 31.39086], [47.68219, 31.00004], [48.03221, 30.9967], [48.02443, 30.4789], [48.14585, 30.44133], [48.18321, 30.39703], [48.19425, 30.32796], [48.21279, 30.31644], [48.24385, 30.33846], [48.26393, 30.3408], [48.41117, 30.19846], [48.41671, 30.17254], [48.38714, 30.13485], [48.38869, 30.11062], [48.43384, 30.08233], [48.4494, 30.04456], [48.44785, 30.00148], [48.51011, 29.96238], [48.61441, 29.93675], [48.83867, 29.78572], [49.98877, 27.87827], [50.37726, 27.89227], [54.39838, 25.68383], [55.14145, 25.62624], [55.81777, 26.18798], [56.2644, 26.58649], [56.68954, 26.76645], [56.79239, 26.41236], [56.82555, 25.7713], [56.86325, 25.03856], [61.46682, 24.57869], [61.6433, 25.27541], [61.683, 25.66638], [61.83968, 25.7538], [61.83831, 26.07249], [61.89391, 26.26251], [62.05117, 26.31647], [62.21304, 26.26601], [62.31484, 26.528], [62.77352, 26.64099], [63.1889, 26.65072], [63.18688, 26.83844], [63.25005, 26.84212], [63.25005, 27.08692], [63.32283, 27.14437], [63.19649, 27.25674], [62.80604, 27.22412], [62.79684, 27.34381], [62.84905, 27.47627], [62.7638, 28.02992], [62.79412, 28.28108], [62.59499, 28.24842], [62.40259, 28.42703], [61.93581, 28.55284], [61.65978, 28.77937], [61.53765, 29.00507], [61.31508, 29.38903], [60.87231, 29.86514], [61.80829, 30.84224], [61.78268, 30.92724], [61.8335, 30.97669], [61.83257, 31.0452], [61.80957, 31.12576], [61.80569, 31.16167], [61.70929, 31.37391], [60.84541, 31.49561], [60.86191, 32.22565], [60.56485, 33.12944], [60.88908, 33.50219], [60.91133, 33.55596], [60.69573, 33.56054], [60.57762, 33.59772], [60.5485, 33.73422], [60.5838, 33.80793], [60.50209, 34.13992], [60.66502, 34.31539], [60.91321, 34.30411], [60.72316, 34.52857], [60.99922, 34.63064], [61.00197, 34.70631], [61.06926, 34.82139], [61.12831, 35.09938], [61.0991, 35.27845], [61.18187, 35.30249], [61.27371, 35.61482], [61.22719, 35.67038], [61.26152, 35.80749], [61.22444, 35.92879], [61.12007, 35.95992], [61.22719, 36.12759], [61.1393, 36.38782], [61.18187, 36.55348], [61.14516, 36.64644], [60.34767, 36.63214], [60.00768, 37.04102], [59.74678, 37.12499], [59.55178, 37.13594], [59.39385, 37.34257], [59.39797, 37.47892], [59.33507, 37.53146], [59.22905, 37.51161], [58.9338, 37.67374], [58.6921, 37.64548], [58.5479, 37.70526], [58.47786, 37.6433], [58.39959, 37.63134], [58.22999, 37.6856], [58.21399, 37.77281], [57.79534, 37.89299], [57.35042, 37.98546], [57.37236, 38.09321], [57.21169, 38.28965], [57.03453, 38.18717], [56.73928, 38.27887], [56.62255, 38.24005], [56.43303, 38.26054], [56.32454, 38.18502], [56.33278, 38.08132], [55.97847, 38.08024], [55.76561, 38.12238], [55.44152, 38.08564], [55.13412, 37.94705], [54.851, 37.75739], [54.77684, 37.62264], [54.81804, 37.61285], [54.77822, 37.51597], [54.67247, 37.43532], [54.58664, 37.45809], [54.36211, 37.34912], [54.24565, 37.32047], [53.89734, 37.3464], [48.88288, 38.43975], [48.84969, 38.45015], [48.81072, 38.44853], [48.78979, 38.45026], [48.70001, 38.40564], [48.62217, 38.40198], [48.58793, 38.45076], [48.45084, 38.61013], [48.3146, 38.59958], [48.24773, 38.71883], [48.02581, 38.82705], [48.01409, 38.90333], [48.07734, 38.91616], [48.08627, 38.94434], [48.28437, 38.97186], [48.33884, 39.03022], [48.31239, 39.09278], [48.15361, 39.19419], [48.12404, 39.25208], [48.15984, 39.30028], [48.37385, 39.37584], [48.34264, 39.42935], [47.98977, 39.70999], [47.84774, 39.66285], [47.50099, 39.49615], [47.38978, 39.45999], [47.31301, 39.37492], [47.05927, 39.24846], [47.05771, 39.20143], [46.95341, 39.13505], [46.92539, 39.16644], [46.83822, 39.13143], [46.75752, 39.03231], [46.53497, 38.86548], [46.34059, 38.92076], [46.20601, 38.85262], [46.14785, 38.84206], [46.06766, 38.87861], [46.00228, 38.87376], [45.94624, 38.89072], [45.90266, 38.87739], [45.83883, 38.90768], [45.65172, 38.95199], [45.6155, 38.94304], [45.6131, 38.964], [45.44966, 38.99243], [45.44811, 39.04927], [45.40452, 39.07224], [45.40148, 39.09007], [45.30489, 39.18333], [45.16168, 39.21952], [45.08751, 39.35052], [45.05932, 39.36435], [44.96746, 39.42998]]]]
24701           }
24702         }, {
24703           type: "Feature",
24704           properties: {
24705             iso1A2: "IS",
24706             iso1A3: "ISL",
24707             iso1N3: "352",
24708             wikidata: "Q189",
24709             nameEn: "Iceland",
24710             groups: ["154", "150", "UN"],
24711             callingCodes: ["354"]
24712           },
24713           geometry: {
24714             type: "MultiPolygon",
24715             coordinates: [[[[-33.15676, 62.62995], [-8.25539, 63.0423], [-15.70914, 69.67442], [-33.15676, 62.62995]]]]
24716           }
24717         }, {
24718           type: "Feature",
24719           properties: {
24720             iso1A2: "IT",
24721             iso1A3: "ITA",
24722             iso1N3: "380",
24723             wikidata: "Q38",
24724             nameEn: "Italy",
24725             groups: ["EU", "039", "150", "UN"],
24726             callingCodes: ["39"]
24727           },
24728           geometry: {
24729             type: "MultiPolygon",
24730             coordinates: [[[[8.95861, 45.96485], [8.97604, 45.96151], [8.97741, 45.98317], [8.96668, 45.98436], [8.95861, 45.96485]]], [[[7.63035, 43.57419], [9.56115, 43.20816], [10.09675, 41.44089], [7.60802, 41.05927], [7.89009, 38.19924], [11.2718, 37.6713], [12.13667, 34.20326], [14.02721, 36.53141], [17.67657, 35.68918], [18.83516, 40.36999], [16.15283, 42.18525], [13.12821, 44.48877], [13.05142, 45.33128], [13.45644, 45.59464], [13.6076, 45.64761], [13.7198, 45.59352], [13.74587, 45.59811], [13.78445, 45.5825], [13.84106, 45.58185], [13.86771, 45.59898], [13.8695, 45.60835], [13.9191, 45.6322], [13.87933, 45.65207], [13.83422, 45.68703], [13.83332, 45.70855], [13.8235, 45.7176], [13.66986, 45.79955], [13.59784, 45.8072], [13.58858, 45.83503], [13.57563, 45.8425], [13.58644, 45.88173], [13.59565, 45.89446], [13.60857, 45.89907], [13.61931, 45.91782], [13.63815, 45.93607], [13.6329, 45.94894], [13.64307, 45.98326], [13.63458, 45.98947], [13.62074, 45.98388], [13.58903, 45.99009], [13.56759, 45.96991], [13.52963, 45.96588], [13.50104, 45.98078], [13.47474, 46.00546], [13.49702, 46.01832], [13.50998, 46.04498], [13.49568, 46.04839], [13.50104, 46.05986], [13.57072, 46.09022], [13.64053, 46.13587], [13.66472, 46.17392], [13.64451, 46.18966], [13.56682, 46.18703], [13.56114, 46.2054], [13.47587, 46.22725], [13.42218, 46.20758], [13.37671, 46.29668], [13.44808, 46.33507], [13.43418, 46.35992], [13.47019, 46.3621], [13.5763, 46.40915], [13.5763, 46.42613], [13.59777, 46.44137], [13.68684, 46.43881], [13.7148, 46.5222], [13.64088, 46.53438], [13.27627, 46.56059], [12.94445, 46.60401], [12.59992, 46.6595], [12.38708, 46.71529], [12.27591, 46.88651], [12.2006, 46.88854], [12.11675, 47.01241], [12.21781, 47.03996], [12.19254, 47.09331], [11.74789, 46.98484], [11.50739, 47.00644], [11.33355, 46.99862], [11.10618, 46.92966], [11.00764, 46.76896], [10.72974, 46.78972], [10.75753, 46.82258], [10.66405, 46.87614], [10.54783, 46.84505], [10.47197, 46.85698], [10.38659, 46.67847], [10.40475, 46.63671], [10.44686, 46.64162], [10.49375, 46.62049], [10.46136, 46.53164], [10.25309, 46.57432], [10.23674, 46.63484], [10.10307, 46.61003], [10.03715, 46.44479], [10.165, 46.41051], [10.10506, 46.3372], [10.17862, 46.25626], [10.14439, 46.22992], [10.07055, 46.21668], [9.95249, 46.38045], [9.73086, 46.35071], [9.71273, 46.29266], [9.57015, 46.2958], [9.46117, 46.37481], [9.45936, 46.50873], [9.40487, 46.46621], [9.36128, 46.5081], [9.28136, 46.49685], [9.25502, 46.43743], [9.29226, 46.32717], [9.24503, 46.23616], [9.01618, 46.04928], [8.99257, 45.9698], [9.09065, 45.89906], [9.06642, 45.8761], [9.04546, 45.84968], [9.04059, 45.8464], [9.03505, 45.83976], [9.03793, 45.83548], [9.03279, 45.82865], [9.0298, 45.82127], [9.00324, 45.82055], [8.99663, 45.83466], [8.9621, 45.83707], [8.94737, 45.84285], [8.91129, 45.8388], [8.93504, 45.86245], [8.94372, 45.86587], [8.93649, 45.86775], [8.88904, 45.95465], [8.86688, 45.96135], [8.85121, 45.97239], [8.8319, 45.9879], [8.79362, 45.99207], [8.78585, 45.98973], [8.79414, 46.00913], [8.85617, 46.0748], [8.80778, 46.10085], [8.75697, 46.10395], [8.62242, 46.12112], [8.45032, 46.26869], [8.46317, 46.43712], [8.42464, 46.46367], [8.30648, 46.41587], [8.31162, 46.38044], [8.08814, 46.26692], [8.16866, 46.17817], [8.11383, 46.11577], [8.02906, 46.10331], [7.98881, 45.99867], [7.9049, 45.99945], [7.85949, 45.91485], [7.56343, 45.97421], [7.10685, 45.85653], [7.04151, 45.92435], [6.95315, 45.85163], [6.80785, 45.83265], [6.80785, 45.71864], [6.98948, 45.63869], [7.00037, 45.509], [7.18019, 45.40071], [7.10572, 45.32924], [7.13115, 45.25386], [7.07074, 45.21228], [6.96706, 45.20841], [6.85144, 45.13226], [6.7697, 45.16044], [6.62803, 45.11175], [6.66981, 45.02324], [6.74791, 45.01939], [6.74519, 44.93661], [6.75518, 44.89915], [6.90774, 44.84322], [6.93499, 44.8664], [7.02217, 44.82519], [7.00401, 44.78782], [7.07484, 44.68073], [7.00582, 44.69364], [6.95133, 44.66264], [6.96042, 44.62129], [6.85507, 44.53072], [6.86233, 44.49834], [6.94504, 44.43112], [6.88784, 44.42043], [6.89171, 44.36637], [6.98221, 44.28289], [7.00764, 44.23736], [7.16929, 44.20352], [7.27827, 44.1462], [7.34547, 44.14359], [7.36364, 44.11882], [7.62155, 44.14881], [7.63245, 44.17877], [7.68694, 44.17487], [7.66878, 44.12795], [7.72508, 44.07578], [7.6597, 44.03009], [7.66848, 43.99943], [7.65266, 43.9763], [7.60771, 43.95772], [7.56858, 43.94506], [7.56075, 43.89932], [7.51162, 43.88301], [7.49355, 43.86551], [7.50423, 43.84345], [7.53006, 43.78405], [7.63035, 43.57419]], [[12.45181, 41.90056], [12.44834, 41.90095], [12.44582, 41.90194], [12.44815, 41.90326], [12.44984, 41.90545], [12.45091, 41.90625], [12.45543, 41.90738], [12.45561, 41.90629], [12.45762, 41.9058], [12.45755, 41.9033], [12.45826, 41.90281], [12.45834, 41.90174], [12.4577, 41.90115], [12.45691, 41.90125], [12.45626, 41.90172], [12.45435, 41.90143], [12.45446, 41.90028], [12.45181, 41.90056]], [[12.45648, 43.89369], [12.44184, 43.90498], [12.41641, 43.89991], [12.40935, 43.9024], [12.41233, 43.90956], [12.40733, 43.92379], [12.41551, 43.92984], [12.41165, 43.93769], [12.40506, 43.94325], [12.40415, 43.95485], [12.41414, 43.95273], [12.42005, 43.9578], [12.43662, 43.95698], [12.44684, 43.96597], [12.46205, 43.97463], [12.47853, 43.98052], [12.49406, 43.98492], [12.50678, 43.99113], [12.51463, 43.99122], [12.5154, 43.98508], [12.51064, 43.98165], [12.51109, 43.97201], [12.50622, 43.97131], [12.50875, 43.96198], [12.50655, 43.95796], [12.51427, 43.94897], [12.51553, 43.94096], [12.50496, 43.93017], [12.50269, 43.92363], [12.49724, 43.92248], [12.49247, 43.91774], [12.49429, 43.90973], [12.48771, 43.89706], [12.45648, 43.89369]]]]
24731           }
24732         }, {
24733           type: "Feature",
24734           properties: {
24735             iso1A2: "JE",
24736             iso1A3: "JEY",
24737             iso1N3: "832",
24738             wikidata: "Q785",
24739             nameEn: "Bailiwick of Jersey",
24740             country: "GB",
24741             groups: ["830", "Q185086", "154", "150", "UN"],
24742             driveSide: "left",
24743             roadSpeedUnit: "mph",
24744             roadHeightUnit: "ft",
24745             callingCodes: ["44 01534"]
24746           },
24747           geometry: {
24748             type: "MultiPolygon",
24749             coordinates: [[[[-2.00491, 48.86706], [-1.83944, 49.23037], [-2.09454, 49.46288], [-2.65349, 49.15373], [-2.00491, 48.86706]]]]
24750           }
24751         }, {
24752           type: "Feature",
24753           properties: {
24754             iso1A2: "JM",
24755             iso1A3: "JAM",
24756             iso1N3: "388",
24757             wikidata: "Q766",
24758             nameEn: "Jamaica",
24759             aliases: ["JA"],
24760             groups: ["029", "003", "419", "019", "UN"],
24761             driveSide: "left",
24762             callingCodes: ["1 876", "1 658"]
24763           },
24764           geometry: {
24765             type: "MultiPolygon",
24766             coordinates: [[[[-74.09729, 17.36817], [-78.9741, 19.59515], [-78.34606, 16.57862], [-74.09729, 17.36817]]]]
24767           }
24768         }, {
24769           type: "Feature",
24770           properties: {
24771             iso1A2: "JO",
24772             iso1A3: "JOR",
24773             iso1N3: "400",
24774             wikidata: "Q810",
24775             nameEn: "Jordan",
24776             groups: ["145", "142", "UN"],
24777             callingCodes: ["962"]
24778           },
24779           geometry: {
24780             type: "MultiPolygon",
24781             coordinates: [[[[39.04251, 32.30203], [38.98762, 32.47694], [39.08202, 32.50304], [38.79171, 33.37328], [36.83946, 32.31293], [36.40959, 32.37908], [36.23948, 32.50108], [36.20875, 32.49529], [36.20379, 32.52751], [36.08074, 32.51463], [36.02239, 32.65911], [35.96633, 32.66237], [35.93307, 32.71966], [35.88405, 32.71321], [35.75983, 32.74803], [35.68467, 32.70715], [35.66527, 32.681], [35.61669, 32.67999], [35.59813, 32.65159], [35.56614, 32.64393], [35.57485, 32.48669], [35.55494, 32.42687], [35.55807, 32.38674], [35.57111, 32.21877], [35.52012, 32.04076], [35.54375, 31.96587], [35.52758, 31.9131], [35.55941, 31.76535], [35.47672, 31.49578], [35.40316, 31.25535], [35.43658, 31.12444], [35.41371, 30.95565], [35.33984, 30.8802], [35.33456, 30.81224], [35.29311, 30.71365], [35.21379, 30.60401], [35.19595, 30.50297], [35.16218, 30.43535], [35.19183, 30.34636], [35.14108, 30.07374], [35.02147, 29.66343], [34.98207, 29.58147], [34.97718, 29.54294], [34.92298, 29.45305], [34.8812, 29.36878], [36.07081, 29.18469], [36.50005, 29.49696], [36.75083, 29.86903], [37.4971, 29.99949], [37.66395, 30.33245], [37.99354, 30.49998], [36.99791, 31.50081], [38.99233, 31.99721], [39.29903, 32.23259], [39.26157, 32.35555], [39.04251, 32.30203]]]]
24782           }
24783         }, {
24784           type: "Feature",
24785           properties: {
24786             iso1A2: "JP",
24787             iso1A3: "JPN",
24788             iso1N3: "392",
24789             wikidata: "Q17",
24790             nameEn: "Japan",
24791             groups: ["030", "142", "UN"],
24792             driveSide: "left",
24793             callingCodes: ["81"]
24794           },
24795           geometry: {
24796             type: "MultiPolygon",
24797             coordinates: [[[[145.82361, 43.38904], [145.23667, 43.76813], [145.82343, 44.571], [140.9182, 45.92937], [133.61399, 37.41], [129.2669, 34.87122], [122.26612, 25.98197], [123.92912, 17.8782], [155.16731, 23.60141], [145.82361, 43.38904]]]]
24798           }
24799         }, {
24800           type: "Feature",
24801           properties: {
24802             iso1A2: "KE",
24803             iso1A3: "KEN",
24804             iso1N3: "404",
24805             wikidata: "Q114",
24806             nameEn: "Kenya",
24807             groups: ["014", "202", "002", "UN"],
24808             driveSide: "left",
24809             callingCodes: ["254"]
24810           },
24811           geometry: {
24812             type: "MultiPolygon",
24813             coordinates: [[[[35.9419, 4.61933], [35.51424, 4.61643], [35.42366, 4.76969], [35.47843, 4.91872], [35.30992, 4.90402], [35.34151, 5.02364], [34.47601, 4.72162], [33.9873, 4.23316], [34.06046, 4.15235], [34.15429, 3.80464], [34.45815, 3.67385], [34.44922, 3.51627], [34.39112, 3.48802], [34.41794, 3.44342], [34.40006, 3.37949], [34.45815, 3.18319], [34.56242, 3.11478], [34.60114, 2.93034], [34.65774, 2.8753], [34.73967, 2.85447], [34.78137, 2.76223], [34.77244, 2.70272], [34.95267, 2.47209], [34.90947, 2.42447], [34.98692, 1.97348], [34.9899, 1.6668], [34.92734, 1.56109], [34.87819, 1.5596], [34.7918, 1.36752], [34.82606, 1.30944], [34.82606, 1.26626], [34.80223, 1.22754], [34.67562, 1.21265], [34.58029, 1.14712], [34.57427, 1.09868], [34.52369, 1.10692], [34.43349, 0.85254], [34.40041, 0.80266], [34.31516, 0.75693], [34.27345, 0.63182], [34.20196, 0.62289], [34.13493, 0.58118], [34.11408, 0.48884], [34.08727, 0.44713], [34.10067, 0.36372], [33.90936, 0.10581], [33.98449, -0.13079], [33.9264, -0.54188], [33.93107, -0.99298], [34.02286, -1.00779], [34.03084, -1.05101], [34.0824, -1.02264], [37.67199, -3.06222], [37.71745, -3.304], [37.5903, -3.42735], [37.63099, -3.50723], [37.75036, -3.54243], [37.81321, -3.69179], [39.21631, -4.67835], [39.44306, -4.93877], [39.62121, -4.68136], [41.75542, -1.85308], [41.56362, -1.66375], [41.56, -1.59812], [41.00099, -0.83068], [40.98767, 2.82959], [41.31368, 3.14314], [41.89488, 3.97375], [41.1754, 3.94079], [40.77498, 4.27683], [39.86043, 3.86974], [39.76808, 3.67058], [39.58339, 3.47434], [39.55132, 3.39634], [39.51551, 3.40895], [39.49444, 3.45521], [39.19954, 3.47834], [39.07736, 3.5267], [38.91938, 3.51198], [38.52336, 3.62551], [38.45812, 3.60445], [38.14168, 3.62487], [37.07724, 4.33503], [36.84474, 4.44518], [36.03924, 4.44406], [35.95449, 4.53244], [35.9419, 4.61933]]]]
24814           }
24815         }, {
24816           type: "Feature",
24817           properties: {
24818             iso1A2: "KG",
24819             iso1A3: "KGZ",
24820             iso1N3: "417",
24821             wikidata: "Q813",
24822             nameEn: "Kyrgyzstan",
24823             groups: ["143", "142", "UN"],
24824             callingCodes: ["996"]
24825           },
24826           geometry: {
24827             type: "MultiPolygon",
24828             coordinates: [[[[74.88756, 42.98612], [74.75, 42.99029], [74.70331, 43.02519], [74.64615, 43.05881], [74.57491, 43.13702], [74.22489, 43.24657], [73.55634, 43.03071], [73.50992, 42.82356], [73.44393, 42.43098], [71.88792, 42.83578], [71.62405, 42.76613], [71.53272, 42.8014], [71.2724, 42.77853], [71.22785, 42.69248], [71.17807, 42.67381], [71.15232, 42.60486], [70.97717, 42.50147], [70.85973, 42.30188], [70.94483, 42.26238], [71.13263, 42.28356], [71.28719, 42.18033], [70.69777, 41.92554], [70.17682, 41.5455], [70.48909, 41.40335], [70.67586, 41.47953], [70.78572, 41.36419], [70.77885, 41.24813], [70.86263, 41.23833], [70.9615, 41.16393], [71.02193, 41.19494], [71.11806, 41.15359], [71.25813, 41.18796], [71.27187, 41.11015], [71.34877, 41.16807], [71.40198, 41.09436], [71.46148, 41.13958], [71.43814, 41.19644], [71.46688, 41.31883], [71.57227, 41.29175], [71.6787, 41.42111], [71.65914, 41.49599], [71.73054, 41.54713], [71.71132, 41.43012], [71.76625, 41.4466], [71.83914, 41.3546], [71.91457, 41.2982], [71.85964, 41.19081], [72.07249, 41.11739], [72.10745, 41.15483], [72.16433, 41.16483], [72.17594, 41.15522], [72.14864, 41.13363], [72.1792, 41.10621], [72.21061, 41.05607], [72.17594, 41.02377], [72.18339, 40.99571], [72.324, 41.03381], [72.34026, 41.04539], [72.34757, 41.06104], [72.36138, 41.04384], [72.38511, 41.02785], [72.45206, 41.03018], [72.48742, 40.97136], [72.55109, 40.96046], [72.59136, 40.86947], [72.68157, 40.84942], [72.84291, 40.85512], [72.94454, 40.8094], [73.01869, 40.84681], [73.13267, 40.83512], [73.13412, 40.79122], [73.0612, 40.76678], [72.99133, 40.76457], [72.93296, 40.73089], [72.8722, 40.71111], [72.85372, 40.7116], [72.84754, 40.67229], [72.80137, 40.67856], [72.74866, 40.60873], [72.74894, 40.59592], [72.75982, 40.57273], [72.74862, 40.57131], [72.74768, 40.58051], [72.73995, 40.58409], [72.69579, 40.59778], [72.66713, 40.59076], [72.66713, 40.5219], [72.47795, 40.5532], [72.40517, 40.61917], [72.34406, 40.60144], [72.41714, 40.55736], [72.38384, 40.51535], [72.41513, 40.50856], [72.44191, 40.48222], [72.40346, 40.4007], [72.24368, 40.46091], [72.18648, 40.49893], [71.96401, 40.31907], [72.05464, 40.27586], [71.85002, 40.25647], [71.82646, 40.21872], [71.73054, 40.14818], [71.71719, 40.17886], [71.69621, 40.18492], [71.70569, 40.20391], [71.68386, 40.26984], [71.61931, 40.26775], [71.61725, 40.20615], [71.51549, 40.22986], [71.51215, 40.26943], [71.4246, 40.28619], [71.36663, 40.31593], [71.13042, 40.34106], [71.05901, 40.28765], [70.95789, 40.28761], [70.9818, 40.22392], [70.80495, 40.16813], [70.7928, 40.12797], [70.65827, 40.0981], [70.65946, 39.9878], [70.58912, 39.95211], [70.55033, 39.96619], [70.47557, 39.93216], [70.57384, 39.99394], [70.58297, 40.00891], [70.01283, 40.23288], [69.67001, 40.10639], [69.64704, 40.12165], [69.57615, 40.10524], [69.55555, 40.12296], [69.53794, 40.11833], [69.53855, 40.0887], [69.5057, 40.03277], [69.53615, 39.93991], [69.43557, 39.92877], [69.43134, 39.98431], [69.35649, 40.01994], [69.26938, 39.8127], [69.3594, 39.52516], [69.68677, 39.59281], [69.87491, 39.53882], [70.11111, 39.58223], [70.2869, 39.53141], [70.44757, 39.60128], [70.64087, 39.58792], [70.7854, 39.38933], [71.06418, 39.41586], [71.08752, 39.50704], [71.49814, 39.61397], [71.55856, 39.57588], [71.5517, 39.45722], [71.62688, 39.44056], [71.76816, 39.45456], [71.80164, 39.40631], [71.7522, 39.32031], [71.79202, 39.27355], [71.90601, 39.27674], [72.04059, 39.36704], [72.09689, 39.26823], [72.17242, 39.2661], [72.23834, 39.17248], [72.33173, 39.33093], [72.62027, 39.39696], [72.85934, 39.35116], [73.18454, 39.35536], [73.31912, 39.38615], [73.45096, 39.46677], [73.59831, 39.46425], [73.87018, 39.47879], [73.94683, 39.60733], [73.92354, 39.69565], [73.9051, 39.75073], [73.83006, 39.76136], [73.97049, 40.04378], [74.25533, 40.13191], [74.35063, 40.09742], [74.69875, 40.34668], [74.85996, 40.32857], [74.78168, 40.44886], [74.82013, 40.52197], [75.08243, 40.43945], [75.22834, 40.45382], [75.5854, 40.66874], [75.69663, 40.28642], [75.91361, 40.2948], [75.96168, 40.38064], [76.33659, 40.3482], [76.5261, 40.46114], [76.75681, 40.95354], [76.99302, 41.0696], [77.28004, 41.0033], [77.3693, 41.0375], [77.52723, 41.00227], [77.76206, 41.01574], [77.81287, 41.14307], [78.12873, 41.23091], [78.15757, 41.38565], [78.3732, 41.39603], [79.92977, 42.04113], [80.17842, 42.03211], [80.17807, 42.21166], [79.97364, 42.42816], [79.52921, 42.44778], [79.19763, 42.804], [78.91502, 42.76839], [78.48469, 42.89649], [75.82823, 42.94848], [75.72174, 42.79672], [75.29966, 42.86183], [75.22619, 42.85528], [74.88756, 42.98612]], [[70.74189, 39.86319], [70.63105, 39.77923], [70.59667, 39.83542], [70.54998, 39.85137], [70.52631, 39.86989], [70.53651, 39.89155], [70.74189, 39.86319]], [[71.86463, 39.98598], [71.84316, 39.95582], [71.7504, 39.93701], [71.71511, 39.96348], [71.78838, 40.01404], [71.86463, 39.98598]], [[71.21139, 40.03369], [71.1427, 39.95026], [71.23067, 39.93581], [71.16101, 39.88423], [71.10531, 39.91354], [71.04979, 39.89808], [71.10501, 39.95568], [71.09063, 39.99], [71.11668, 39.99291], [71.11037, 40.01984], [71.01035, 40.05481], [71.00236, 40.18154], [71.06305, 40.1771], [71.12218, 40.03052], [71.21139, 40.03369]]]]
24829           }
24830         }, {
24831           type: "Feature",
24832           properties: {
24833             iso1A2: "KH",
24834             iso1A3: "KHM",
24835             iso1N3: "116",
24836             wikidata: "Q424",
24837             nameEn: "Cambodia",
24838             groups: ["035", "142", "UN"],
24839             callingCodes: ["855"]
24840           },
24841           geometry: {
24842             type: "MultiPolygon",
24843             coordinates: [[[[105.87328, 11.55953], [105.81645, 11.56876], [105.80867, 11.60536], [105.8507, 11.66635], [105.88962, 11.67854], [105.95188, 11.63738], [106.00792, 11.7197], [106.02038, 11.77457], [106.06708, 11.77761], [106.13158, 11.73283], [106.18539, 11.75171], [106.26478, 11.72122], [106.30525, 11.67549], [106.37219, 11.69836], [106.44691, 11.66787], [106.45158, 11.68616], [106.41577, 11.76999], [106.44535, 11.8279], [106.44068, 11.86294], [106.4687, 11.86751], [106.4111, 11.97413], [106.70687, 11.96956], [106.79405, 12.0807], [106.92325, 12.06548], [106.99953, 12.08983], [107.15831, 12.27547], [107.34511, 12.33327], [107.42917, 12.24657], [107.4463, 12.29373], [107.55059, 12.36824], [107.5755, 12.52177], [107.55993, 12.7982], [107.49611, 12.88926], [107.49144, 13.01215], [107.62843, 13.3668], [107.61909, 13.52577], [107.53503, 13.73908], [107.45252, 13.78897], [107.46498, 13.91593], [107.44318, 13.99751], [107.38247, 13.99147], [107.35757, 14.02319], [107.37158, 14.07906], [107.33577, 14.11832], [107.40427, 14.24509], [107.39493, 14.32655], [107.44941, 14.41552], [107.48521, 14.40346], [107.52569, 14.54665], [107.52102, 14.59034], [107.55371, 14.628], [107.54361, 14.69092], [107.47238, 14.61523], [107.44435, 14.52785], [107.37897, 14.54443], [107.3276, 14.58812], [107.29803, 14.58963], [107.26534, 14.54292], [107.256, 14.48716], [107.21241, 14.48716], [107.17038, 14.41782], [107.09722, 14.3937], [107.03962, 14.45099], [107.04585, 14.41782], [106.98825, 14.36806], [106.9649, 14.3198], [106.90574, 14.33639], [106.8497, 14.29416], [106.80767, 14.31226], [106.73762, 14.42687], [106.63333, 14.44194], [106.59908, 14.50977], [106.57106, 14.50525], [106.54148, 14.59565], [106.50723, 14.58963], [106.45898, 14.55045], [106.47766, 14.50977], [106.43874, 14.52032], [106.40916, 14.45249], [106.32355, 14.44043], [106.25194, 14.48415], [106.21302, 14.36203], [106.00131, 14.36957], [105.99509, 14.32734], [106.02311, 14.30623], [106.04801, 14.20363], [106.10872, 14.18401], [106.11962, 14.11307], [106.18656, 14.06324], [106.16632, 14.01794], [106.10094, 13.98471], [106.10405, 13.9137], [105.90791, 13.92881], [105.78182, 14.02247], [105.78338, 14.08438], [105.5561, 14.15684], [105.44869, 14.10703], [105.36775, 14.09948], [105.2759, 14.17496], [105.20894, 14.34967], [105.17748, 14.34432], [105.14012, 14.23873], [105.08408, 14.20402], [105.02804, 14.23722], [104.97667, 14.38806], [104.69335, 14.42726], [104.55014, 14.36091], [104.27616, 14.39861], [103.93836, 14.3398], [103.70175, 14.38052], [103.71109, 14.4348], [103.53518, 14.42575], [103.39353, 14.35639], [103.16469, 14.33075], [102.93275, 14.19044], [102.91251, 14.01531], [102.77864, 13.93374], [102.72727, 13.77806], [102.56848, 13.69366], [102.5481, 13.6589], [102.58635, 13.6286], [102.62483, 13.60883], [102.57573, 13.60461], [102.5358, 13.56933], [102.44601, 13.5637], [102.36859, 13.57488], [102.33828, 13.55613], [102.361, 13.50551], [102.35563, 13.47307], [102.35692, 13.38274], [102.34611, 13.35618], [102.36001, 13.31142], [102.36146, 13.26006], [102.43422, 13.09061], [102.46011, 13.08057], [102.52275, 12.99813], [102.48694, 12.97537], [102.49335, 12.92711], [102.53053, 12.77506], [102.4994, 12.71736], [102.51963, 12.66117], [102.57567, 12.65358], [102.7796, 12.43781], [102.78116, 12.40284], [102.73134, 12.37091], [102.70176, 12.1686], [102.77026, 12.06815], [102.78427, 11.98746], [102.83957, 11.8519], [102.90973, 11.75613], [102.91449, 11.65512], [102.52395, 11.25257], [102.47649, 9.66162], [103.99198, 10.48391], [104.43778, 10.42386], [104.47963, 10.43046], [104.49869, 10.4057], [104.59018, 10.53073], [104.87933, 10.52833], [104.95094, 10.64003], [105.09571, 10.72722], [105.02722, 10.89236], [105.08326, 10.95656], [105.11449, 10.96332], [105.34011, 10.86179], [105.42884, 10.96878], [105.50045, 10.94586], [105.77751, 11.03671], [105.86376, 10.89839], [105.84603, 10.85873], [105.93403, 10.83853], [105.94535, 10.9168], [106.06708, 10.8098], [106.18539, 10.79451], [106.14301, 10.98176], [106.20095, 10.97795], [106.1757, 11.07301], [106.1527, 11.10476], [106.10444, 11.07879], [105.86782, 11.28343], [105.88962, 11.43605], [105.87328, 11.55953]]]]
24844           }
24845         }, {
24846           type: "Feature",
24847           properties: {
24848             iso1A2: "KI",
24849             iso1A3: "KIR",
24850             iso1N3: "296",
24851             wikidata: "Q710",
24852             nameEn: "Kiribati",
24853             groups: ["057", "009", "UN"],
24854             driveSide: "left",
24855             callingCodes: ["686"]
24856           },
24857           geometry: {
24858             type: "MultiPolygon",
24859             coordinates: [[[[169, 3.9], [169, -3.5], [178, -3.5], [178, 3.9], [169, 3.9]]], [[[-161.06795, 5.2462], [-158.12991, -1.86122], [-175.33482, -1.40631], [-175.31804, -7.54825], [-156.50903, -7.4975], [-156.48634, -15.52824], [-135.59706, -4.70473], [-161.06795, 5.2462]]]]
24860           }
24861         }, {
24862           type: "Feature",
24863           properties: {
24864             iso1A2: "KM",
24865             iso1A3: "COM",
24866             iso1N3: "174",
24867             wikidata: "Q970",
24868             nameEn: "Comoros",
24869             groups: ["014", "202", "002", "UN"],
24870             callingCodes: ["269"]
24871           },
24872           geometry: {
24873             type: "MultiPolygon",
24874             coordinates: [[[[42.63904, -10.02522], [43.28731, -13.97126], [45.4971, -11.75965], [42.63904, -10.02522]]]]
24875           }
24876         }, {
24877           type: "Feature",
24878           properties: {
24879             iso1A2: "KN",
24880             iso1A3: "KNA",
24881             iso1N3: "659",
24882             wikidata: "Q763",
24883             nameEn: "St. Kitts and Nevis",
24884             groups: ["029", "003", "419", "019", "UN"],
24885             driveSide: "left",
24886             roadSpeedUnit: "mph",
24887             callingCodes: ["1 869"]
24888           },
24889           geometry: {
24890             type: "MultiPolygon",
24891             coordinates: [[[[-62.29333, 17.43155], [-62.76692, 17.64353], [-63.09677, 17.21372], [-62.63813, 16.65446], [-62.29333, 17.43155]]]]
24892           }
24893         }, {
24894           type: "Feature",
24895           properties: {
24896             iso1A2: "KP",
24897             iso1A3: "PRK",
24898             iso1N3: "408",
24899             wikidata: "Q423",
24900             nameEn: "North Korea",
24901             groups: ["030", "142", "UN"],
24902             callingCodes: ["850"]
24903           },
24904           geometry: {
24905             type: "MultiPolygon",
24906             coordinates: [[[[130.26095, 42.9027], [130.09764, 42.91425], [130.12957, 42.98361], [129.96409, 42.97306], [129.95082, 43.01051], [129.8865, 43.00395], [129.85261, 42.96494], [129.83277, 42.86746], [129.80719, 42.79218], [129.7835, 42.76521], [129.77183, 42.69435], [129.75294, 42.59409], [129.72541, 42.43739], [129.60482, 42.44461], [129.54701, 42.37254], [129.42882, 42.44702], [129.28541, 42.41574], [129.22423, 42.3553], [129.22285, 42.26491], [129.15178, 42.17224], [128.96068, 42.06657], [128.94007, 42.03537], [128.04487, 42.01769], [128.15119, 41.74568], [128.30716, 41.60322], [128.20061, 41.40895], [128.18546, 41.41279], [128.12967, 41.37931], [128.03311, 41.39232], [128.02633, 41.42103], [127.92943, 41.44291], [127.29712, 41.49473], [127.17841, 41.59714], [126.90729, 41.79955], [126.60631, 41.65565], [126.53189, 41.35206], [126.242, 41.15454], [126.00335, 40.92835], [125.76869, 40.87908], [125.71172, 40.85223], [124.86913, 40.45387], [124.40719, 40.13655], [124.38556, 40.11047], [124.3322, 40.05573], [124.37089, 40.03004], [124.35029, 39.95639], [124.23201, 39.9248], [124.17532, 39.8232], [123.90497, 38.79949], [123.85601, 37.49093], [124.67666, 38.05679], [124.84224, 37.977], [124.87921, 37.80827], [125.06408, 37.66334], [125.37112, 37.62643], [125.81159, 37.72949], [126.13074, 37.70512], [126.18776, 37.74728], [126.19097, 37.81462], [126.24402, 37.83113], [126.43239, 37.84095], [126.46818, 37.80873], [126.56709, 37.76857], [126.59918, 37.76364], [126.66067, 37.7897], [126.68793, 37.83728], [126.68793, 37.9175], [126.67023, 37.95852], [126.84961, 38.0344], [126.88106, 38.10246], [126.95887, 38.1347], [126.95338, 38.17735], [127.04479, 38.25518], [127.15749, 38.30722], [127.38727, 38.33227], [127.49672, 38.30647], [127.55013, 38.32257], [128.02917, 38.31861], [128.27652, 38.41657], [128.31105, 38.58462], [128.37487, 38.62345], [128.65655, 38.61914], [131.95041, 41.5445], [130.65022, 42.32281], [130.66367, 42.38024], [130.64181, 42.41422], [130.60805, 42.4317], [130.56835, 42.43281], [130.55143, 42.52158], [130.50123, 42.61636], [130.44361, 42.54849], [130.41826, 42.6011], [130.2385, 42.71127], [130.23068, 42.80125], [130.26095, 42.9027]]]]
24907           }
24908         }, {
24909           type: "Feature",
24910           properties: {
24911             iso1A2: "KR",
24912             iso1A3: "KOR",
24913             iso1N3: "410",
24914             wikidata: "Q884",
24915             nameEn: "South Korea",
24916             groups: ["030", "142", "UN"],
24917             callingCodes: ["82"]
24918           },
24919           geometry: {
24920             type: "MultiPolygon",
24921             coordinates: [[[[133.11729, 37.53115], [128.65655, 38.61914], [128.37487, 38.62345], [128.31105, 38.58462], [128.27652, 38.41657], [128.02917, 38.31861], [127.55013, 38.32257], [127.49672, 38.30647], [127.38727, 38.33227], [127.15749, 38.30722], [127.04479, 38.25518], [126.95338, 38.17735], [126.95887, 38.1347], [126.88106, 38.10246], [126.84961, 38.0344], [126.67023, 37.95852], [126.68793, 37.9175], [126.68793, 37.83728], [126.66067, 37.7897], [126.59918, 37.76364], [126.56709, 37.76857], [126.46818, 37.80873], [126.43239, 37.84095], [126.24402, 37.83113], [126.19097, 37.81462], [126.18776, 37.74728], [126.13074, 37.70512], [125.81159, 37.72949], [125.37112, 37.62643], [125.06408, 37.66334], [124.87921, 37.80827], [124.84224, 37.977], [124.67666, 38.05679], [123.85601, 37.49093], [122.80525, 33.30571], [125.99728, 32.63328], [129.2669, 34.87122], [133.11729, 37.53115]]]]
24922           }
24923         }, {
24924           type: "Feature",
24925           properties: {
24926             iso1A2: "KW",
24927             iso1A3: "KWT",
24928             iso1N3: "414",
24929             wikidata: "Q817",
24930             nameEn: "Kuwait",
24931             groups: ["145", "142", "UN"],
24932             callingCodes: ["965"]
24933           },
24934           geometry: {
24935             type: "MultiPolygon",
24936             coordinates: [[[[49.00421, 28.81495], [48.59531, 29.66815], [48.40479, 29.85763], [48.17332, 30.02448], [48.06782, 30.02906], [48.01114, 29.98906], [47.7095, 30.10453], [47.37192, 30.10421], [47.15166, 30.01044], [46.89695, 29.50584], [46.5527, 29.10283], [47.46202, 29.0014], [47.58376, 28.83382], [47.59863, 28.66798], [47.70561, 28.5221], [48.42991, 28.53628], [49.00421, 28.81495]]]]
24937           }
24938         }, {
24939           type: "Feature",
24940           properties: {
24941             iso1A2: "KY",
24942             iso1A3: "CYM",
24943             iso1N3: "136",
24944             wikidata: "Q5785",
24945             nameEn: "Cayman Islands",
24946             country: "GB",
24947             groups: ["BOTS", "029", "003", "419", "019", "UN"],
24948             driveSide: "left",
24949             roadSpeedUnit: "mph",
24950             roadHeightUnit: "ft",
24951             callingCodes: ["1 345"]
24952           },
24953           geometry: {
24954             type: "MultiPolygon",
24955             coordinates: [[[[-82.11509, 19.60401], [-80.36068, 18.11751], [-79.32727, 20.06742], [-82.11509, 19.60401]]]]
24956           }
24957         }, {
24958           type: "Feature",
24959           properties: {
24960             iso1A2: "KZ",
24961             iso1A3: "KAZ",
24962             iso1N3: "398",
24963             wikidata: "Q232",
24964             nameEn: "Kazakhstan",
24965             groups: ["143", "142", "UN"],
24966             callingCodes: ["7"]
24967           },
24968           geometry: {
24969             type: "MultiPolygon",
24970             coordinates: [[[[68.90865, 55.38148], [68.19206, 55.18823], [68.26661, 55.09226], [68.21308, 54.98645], [65.20174, 54.55216], [65.24663, 54.35721], [65.11033, 54.33028], [64.97216, 54.4212], [63.97686, 54.29763], [64.02715, 54.22679], [63.91224, 54.20013], [63.80604, 54.27079], [62.58651, 54.05871], [62.56876, 53.94047], [62.45931, 53.90737], [62.38535, 54.03961], [62.00966, 54.04134], [62.03913, 53.94768], [61.65318, 54.02445], [61.56941, 53.95703], [61.47603, 54.08048], [61.3706, 54.08464], [61.26863, 53.92797], [60.99796, 53.93699], [61.14283, 53.90063], [61.22574, 53.80268], [60.90626, 53.62937], [61.55706, 53.57144], [61.57185, 53.50112], [61.37957, 53.45887], [61.29082, 53.50992], [61.14291, 53.41481], [61.19024, 53.30536], [62.14574, 53.09626], [62.12799, 52.99133], [62.0422, 52.96105], [61.23462, 53.03227], [61.05842, 52.92217], [60.71989, 52.75923], [60.71693, 52.66245], [60.84118, 52.63912], [60.84709, 52.52228], [60.98021, 52.50068], [61.05417, 52.35096], [60.78201, 52.22067], [60.72581, 52.15538], [60.48915, 52.15175], [60.19925, 51.99173], [59.99809, 51.98263], [60.09867, 51.87135], [60.50986, 51.7964], [60.36787, 51.66815], [60.5424, 51.61675], [60.92401, 51.61124], [60.95655, 51.48615], [61.50677, 51.40687], [61.55114, 51.32746], [61.6813, 51.25716], [61.56889, 51.23679], [61.4431, 50.80679], [60.81833, 50.6629], [60.31914, 50.67705], [60.17262, 50.83312], [60.01288, 50.8163], [59.81172, 50.54451], [59.51886, 50.49937], [59.48928, 50.64216], [58.87974, 50.70852], [58.3208, 51.15151], [57.75578, 51.13852], [57.74986, 50.93017], [57.44221, 50.88354], [57.17302, 51.11253], [56.17906, 50.93204], [56.11398, 50.7471], [55.67774, 50.54508], [54.72067, 51.03261], [54.56685, 51.01958], [54.71476, 50.61214], [54.55797, 50.52006], [54.41894, 50.61214], [54.46331, 50.85554], [54.12248, 51.11542], [53.69299, 51.23466], [53.46165, 51.49445], [52.54329, 51.48444], [52.36119, 51.74161], [51.8246, 51.67916], [51.77431, 51.49536], [51.301, 51.48799], [51.26254, 51.68466], [50.59695, 51.61859], [50.26859, 51.28677], [49.97277, 51.2405], [49.76866, 51.11067], [49.39001, 51.09396], [49.41959, 50.85927], [49.12673, 50.78639], [48.86936, 50.61589], [48.57946, 50.63278], [48.90782, 50.02281], [48.68352, 49.89546], [48.42564, 49.82283], [48.24519, 49.86099], [48.10044, 50.09242], [47.58551, 50.47867], [47.30448, 50.30894], [47.34589, 50.09308], [47.18319, 49.93721], [46.9078, 49.86707], [46.78398, 49.34026], [47.04658, 49.19834], [47.00857, 49.04921], [46.78392, 48.95352], [46.49011, 48.43019], [47.11516, 48.27188], [47.12107, 47.83687], [47.38731, 47.68176], [47.41689, 47.83687], [47.64973, 47.76559], [48.15348, 47.74545], [48.45173, 47.40818], [48.52326, 47.4102], [49.01136, 46.72716], [48.51142, 46.69268], [48.54988, 46.56267], [49.16518, 46.38542], [49.32259, 46.26944], [49.88945, 46.04554], [49.2134, 44.84989], [52.26048, 41.69249], [52.47884, 41.78034], [52.97575, 42.1308], [54.20635, 42.38477], [54.95182, 41.92424], [55.45471, 41.25609], [56.00314, 41.32584], [55.97584, 44.99322], [55.97584, 44.99328], [55.97584, 44.99338], [55.97584, 44.99343], [55.97584, 44.99348], [55.97584, 44.99353], [55.97584, 44.99359], [55.97584, 44.99369], [55.97584, 44.99374], [55.97584, 44.99384], [55.97584, 44.9939], [55.97584, 44.994], [55.97584, 44.99405], [55.97584, 44.99415], [55.97584, 44.99421], [55.97584, 44.99426], [55.97584, 44.99431], [55.97584, 44.99436], [55.97584, 44.99441], [55.97594, 44.99446], [55.97605, 44.99452], [55.97605, 44.99457], [55.97605, 44.99462], [55.97605, 44.99467], [55.97605, 44.99477], [55.97615, 44.99477], [55.97615, 44.99483], [55.97615, 44.99493], [55.97615, 44.99498], [55.97615, 44.99503], [55.97615, 44.99508], [55.97625, 44.99514], [55.97636, 44.99519], [55.97636, 44.99524], [55.97646, 44.99529], [55.97646, 44.99534], [55.97656, 44.99539], [55.97667, 44.99545], [55.97677, 44.9955], [55.97677, 44.99555], [55.97677, 44.9956], [55.97687, 44.9956], [55.97698, 44.99565], [55.97698, 44.9957], [55.97708, 44.99576], [55.97718, 44.99581], [55.97729, 44.99586], [55.97739, 44.99586], [55.97739, 44.99591], [55.97749, 44.99591], [55.9776, 44.99591], [55.9777, 44.99596], [55.9777, 44.99601], [55.9778, 44.99607], [55.97791, 44.99607], [55.97801, 44.99607], [55.97801, 44.99612], [55.97811, 44.99617], [55.97822, 44.99617], [55.97832, 44.99622], [55.97842, 44.99622], [58.59711, 45.58671], [61.01475, 44.41383], [62.01711, 43.51008], [63.34656, 43.64003], [64.53885, 43.56941], [64.96464, 43.74748], [65.18666, 43.48835], [65.53277, 43.31856], [65.85194, 42.85481], [66.09482, 42.93426], [66.00546, 41.94455], [66.53302, 41.87388], [66.69129, 41.1311], [67.9644, 41.14611], [67.98511, 41.02794], [68.08273, 41.08148], [68.1271, 41.0324], [67.96736, 40.83798], [68.49983, 40.56437], [68.63, 40.59358], [68.58444, 40.91447], [68.49983, 40.99669], [68.62221, 41.03019], [68.65662, 40.93861], [68.73945, 40.96989], [68.7217, 41.05025], [69.01308, 41.22804], [69.05006, 41.36183], [69.15137, 41.43078], [69.17701, 41.43769], [69.18528, 41.45175], [69.20439, 41.45391], [69.22671, 41.46298], [69.23332, 41.45847], [69.25059, 41.46693], [69.29778, 41.43673], [69.35554, 41.47211], [69.37468, 41.46555], [69.45081, 41.46246], [69.39485, 41.51518], [69.45751, 41.56863], [69.49545, 41.545], [70.94483, 42.26238], [70.85973, 42.30188], [70.97717, 42.50147], [71.15232, 42.60486], [71.17807, 42.67381], [71.22785, 42.69248], [71.2724, 42.77853], [71.53272, 42.8014], [71.62405, 42.76613], [71.88792, 42.83578], [73.44393, 42.43098], [73.50992, 42.82356], [73.55634, 43.03071], [74.22489, 43.24657], [74.57491, 43.13702], [74.64615, 43.05881], [74.70331, 43.02519], [74.75, 42.99029], [74.88756, 42.98612], [75.22619, 42.85528], [75.29966, 42.86183], [75.72174, 42.79672], [75.82823, 42.94848], [78.48469, 42.89649], [78.91502, 42.76839], [79.19763, 42.804], [79.52921, 42.44778], [79.97364, 42.42816], [80.17807, 42.21166], [80.26841, 42.23797], [80.16892, 42.61137], [80.26886, 42.8366], [80.38169, 42.83142], [80.58999, 42.9011], [80.3735, 43.01557], [80.62913, 43.141], [80.78817, 43.14235], [80.77771, 43.30065], [80.69718, 43.32589], [80.75156, 43.44948], [80.40031, 44.10986], [80.40229, 44.23319], [80.38384, 44.63073], [79.8987, 44.89957], [80.11169, 45.03352], [81.73278, 45.3504], [82.51374, 45.1755], [82.58474, 45.40027], [82.21792, 45.56619], [83.04622, 47.19053], [83.92184, 46.98912], [84.73077, 47.01394], [84.93995, 46.87399], [85.22443, 47.04816], [85.54294, 47.06171], [85.69696, 47.2898], [85.61067, 47.49753], [85.5169, 48.05493], [85.73581, 48.3939], [86.38069, 48.46064], [86.75343, 48.70331], [86.73568, 48.99918], [86.87238, 49.12432], [87.28386, 49.11626], [87.31465, 49.23603], [87.03071, 49.25142], [86.82606, 49.51796], [86.61307, 49.60239], [86.79056, 49.74787], [86.63674, 49.80136], [86.18709, 49.50259], [85.24047, 49.60239], [84.99198, 50.06793], [84.29385, 50.27257], [83.8442, 50.87375], [83.14607, 51.00796], [82.55443, 50.75412], [81.94999, 50.79307], [81.46581, 50.77658], [81.41248, 50.97524], [81.06091, 50.94833], [81.16999, 51.15662], [80.80318, 51.28262], [80.44819, 51.20855], [80.4127, 50.95581], [80.08138, 50.77658], [79.11255, 52.01171], [77.90383, 53.29807], [76.54243, 53.99329], [76.44076, 54.16017], [76.82266, 54.1798], [76.91052, 54.4677], [75.3668, 54.07439], [75.43398, 53.98652], [75.07405, 53.80831], [73.39218, 53.44623], [73.25412, 53.61532], [73.68921, 53.86522], [73.74778, 54.07194], [73.37963, 53.96132], [72.71026, 54.1161], [72.43415, 53.92685], [72.17477, 54.36303], [71.96141, 54.17736], [71.10379, 54.13326], [71.08706, 54.33376], [71.24185, 54.64965], [71.08288, 54.71253], [70.96009, 55.10558], [70.76493, 55.3027], [70.19179, 55.1476], [69.74917, 55.35545], [69.34224, 55.36344], [68.90865, 55.38148]]]]
24971           }
24972         }, {
24973           type: "Feature",
24974           properties: {
24975             iso1A2: "LA",
24976             iso1A3: "LAO",
24977             iso1N3: "418",
24978             wikidata: "Q819",
24979             nameEn: "Laos",
24980             groups: ["035", "142", "UN"],
24981             callingCodes: ["856"]
24982           },
24983           geometry: {
24984             type: "MultiPolygon",
24985             coordinates: [[[[102.1245, 22.43372], [102.03633, 22.46164], [101.98487, 22.42766], [101.91344, 22.44417], [101.90714, 22.38688], [101.86828, 22.38397], [101.7685, 22.50337], [101.68973, 22.46843], [101.61306, 22.27515], [101.56789, 22.28876], [101.53638, 22.24794], [101.60675, 22.13513], [101.57525, 22.13026], [101.62566, 21.96574], [101.7791, 21.83019], [101.74555, 21.72852], [101.83257, 21.61562], [101.80001, 21.57461], [101.7475, 21.5873], [101.7727, 21.51794], [101.74224, 21.48276], [101.74014, 21.30967], [101.84412, 21.25291], [101.83887, 21.20983], [101.76745, 21.21571], [101.79266, 21.19025], [101.7622, 21.14813], [101.70548, 21.14911], [101.66977, 21.20004], [101.60886, 21.17947], [101.59491, 21.18621], [101.6068, 21.23329], [101.54563, 21.25668], [101.29326, 21.17254], [101.2229, 21.23271], [101.26912, 21.36482], [101.19349, 21.41959], [101.2124, 21.56422], [101.15156, 21.56129], [101.16198, 21.52808], [101.00234, 21.39612], [100.80173, 21.2934], [100.72716, 21.31786], [100.63578, 21.05639], [100.55281, 21.02796], [100.50974, 20.88574], [100.64628, 20.88279], [100.60112, 20.8347], [100.51079, 20.82194], [100.36375, 20.82783], [100.1957, 20.68247], [100.08404, 20.36626], [100.09999, 20.31614], [100.09337, 20.26293], [100.11785, 20.24787], [100.1712, 20.24324], [100.16668, 20.2986], [100.22076, 20.31598], [100.25769, 20.3992], [100.33383, 20.4028], [100.37439, 20.35156], [100.41473, 20.25625], [100.44992, 20.23644], [100.4537, 20.19971], [100.47567, 20.19133], [100.51052, 20.14928], [100.55218, 20.17741], [100.58808, 20.15791], [100.5094, 19.87904], [100.398, 19.75047], [100.49604, 19.53504], [100.58219, 19.49164], [100.64606, 19.55884], [100.77231, 19.48324], [100.90302, 19.61901], [101.08928, 19.59748], [101.26545, 19.59242], [101.26991, 19.48324], [101.21347, 19.46223], [101.20604, 19.35296], [101.24911, 19.33334], [101.261, 19.12717], [101.35606, 19.04716], [101.25803, 18.89545], [101.22832, 18.73377], [101.27585, 18.68875], [101.06047, 18.43247], [101.18227, 18.34367], [101.15108, 18.25624], [101.19118, 18.2125], [101.1793, 18.0544], [101.02185, 17.87637], [100.96541, 17.57926], [101.15108, 17.47586], [101.44667, 17.7392], [101.72294, 17.92867], [101.78087, 18.07559], [101.88485, 18.02474], [102.11359, 18.21532], [102.45523, 17.97106], [102.59234, 17.96127], [102.60971, 17.95411], [102.61432, 17.92273], [102.5896, 17.84889], [102.59485, 17.83537], [102.68194, 17.80151], [102.69946, 17.81686], [102.67543, 17.84529], [102.68538, 17.86653], [102.75954, 17.89561], [102.79044, 17.93612], [102.81988, 17.94233], [102.86323, 17.97531], [102.95812, 18.0054], [102.9912, 17.9949], [103.01998, 17.97095], [103.0566, 18.00144], [103.07823, 18.03833], [103.07343, 18.12351], [103.1493, 18.17799], [103.14994, 18.23172], [103.17093, 18.2618], [103.29757, 18.30475], [103.23818, 18.34875], [103.24779, 18.37807], [103.30977, 18.4341], [103.41044, 18.4486], [103.47773, 18.42841], [103.60957, 18.40528], [103.699, 18.34125], [103.82449, 18.33979], [103.85642, 18.28666], [103.93916, 18.33914], [103.97725, 18.33631], [104.06533, 18.21656], [104.10927, 18.10826], [104.21776, 17.99335], [104.2757, 17.86139], [104.35432, 17.82871], [104.45404, 17.66788], [104.69867, 17.53038], [104.80061, 17.39367], [104.80716, 17.19025], [104.73712, 17.01404], [104.7373, 16.91125], [104.76442, 16.84752], [104.7397, 16.81005], [104.76099, 16.69302], [104.73349, 16.565], [104.88057, 16.37311], [105.00262, 16.25627], [105.06204, 16.09792], [105.42001, 16.00657], [105.38508, 15.987], [105.34115, 15.92737], [105.37959, 15.84074], [105.42285, 15.76971], [105.46573, 15.74742], [105.61756, 15.68792], [105.60446, 15.53301], [105.58191, 15.41031], [105.47635, 15.3796], [105.4692, 15.33709], [105.50662, 15.32054], [105.58043, 15.32724], [105.46661, 15.13132], [105.61162, 15.00037], [105.5121, 14.80802], [105.53864, 14.55731], [105.43783, 14.43865], [105.20894, 14.34967], [105.2759, 14.17496], [105.36775, 14.09948], [105.44869, 14.10703], [105.5561, 14.15684], [105.78338, 14.08438], [105.78182, 14.02247], [105.90791, 13.92881], [106.10405, 13.9137], [106.10094, 13.98471], [106.16632, 14.01794], [106.18656, 14.06324], [106.11962, 14.11307], [106.10872, 14.18401], [106.04801, 14.20363], [106.02311, 14.30623], [105.99509, 14.32734], [106.00131, 14.36957], [106.21302, 14.36203], [106.25194, 14.48415], [106.32355, 14.44043], [106.40916, 14.45249], [106.43874, 14.52032], [106.47766, 14.50977], [106.45898, 14.55045], [106.50723, 14.58963], [106.54148, 14.59565], [106.57106, 14.50525], [106.59908, 14.50977], [106.63333, 14.44194], [106.73762, 14.42687], [106.80767, 14.31226], [106.8497, 14.29416], [106.90574, 14.33639], [106.9649, 14.3198], [106.98825, 14.36806], [107.04585, 14.41782], [107.03962, 14.45099], [107.09722, 14.3937], [107.17038, 14.41782], [107.21241, 14.48716], [107.256, 14.48716], [107.26534, 14.54292], [107.29803, 14.58963], [107.3276, 14.58812], [107.37897, 14.54443], [107.44435, 14.52785], [107.47238, 14.61523], [107.54361, 14.69092], [107.51579, 14.79282], [107.59285, 14.87795], [107.48277, 14.93751], [107.46516, 15.00982], [107.61486, 15.0566], [107.61926, 15.13949], [107.58844, 15.20111], [107.62587, 15.2266], [107.60605, 15.37524], [107.62367, 15.42193], [107.53341, 15.40496], [107.50699, 15.48771], [107.3815, 15.49832], [107.34408, 15.62345], [107.27583, 15.62769], [107.27143, 15.71459], [107.21859, 15.74638], [107.21419, 15.83747], [107.34188, 15.89464], [107.39471, 15.88829], [107.46296, 16.01106], [107.44975, 16.08511], [107.33968, 16.05549], [107.25822, 16.13587], [107.14595, 16.17816], [107.15035, 16.26271], [107.09091, 16.3092], [107.02597, 16.31132], [106.97385, 16.30204], [106.96638, 16.34938], [106.88067, 16.43594], [106.88727, 16.52671], [106.84104, 16.55415], [106.74418, 16.41904], [106.65832, 16.47816], [106.66052, 16.56892], [106.61477, 16.60713], [106.58267, 16.6012], [106.59013, 16.62259], [106.55485, 16.68704], [106.55265, 16.86831], [106.52183, 16.87884], [106.51963, 16.92097], [106.54824, 16.92729], [106.55045, 17.0031], [106.50862, 16.9673], [106.43597, 17.01362], [106.31929, 17.20509], [106.29287, 17.3018], [106.24444, 17.24714], [106.18991, 17.28227], [106.09019, 17.36399], [105.85744, 17.63221], [105.76612, 17.67147], [105.60381, 17.89356], [105.64784, 17.96687], [105.46292, 18.22008], [105.38366, 18.15315], [105.15942, 18.38691], [105.10408, 18.43533], [105.1327, 18.58355], [105.19654, 18.64196], [105.12829, 18.70453], [104.64617, 18.85668], [104.5361, 18.97747], [103.87125, 19.31854], [104.06058, 19.43484], [104.10832, 19.51575], [104.05617, 19.61743], [104.06498, 19.66926], [104.23229, 19.70242], [104.41281, 19.70035], [104.53169, 19.61743], [104.64837, 19.62365], [104.68359, 19.72729], [104.8355, 19.80395], [104.8465, 19.91783], [104.9874, 20.09573], [104.91695, 20.15567], [104.86852, 20.14121], [104.61315, 20.24452], [104.62195, 20.36633], [104.72102, 20.40554], [104.66158, 20.47774], [104.47886, 20.37459], [104.40621, 20.3849], [104.38199, 20.47155], [104.63957, 20.6653], [104.27412, 20.91433], [104.11121, 20.96779], [103.98024, 20.91531], [103.82282, 20.8732], [103.73478, 20.6669], [103.68633, 20.66324], [103.45737, 20.82382], [103.38032, 20.79501], [103.21497, 20.89832], [103.12055, 20.89994], [103.03469, 21.05821], [102.97745, 21.05821], [102.89825, 21.24707], [102.80794, 21.25736], [102.88939, 21.3107], [102.94223, 21.46034], [102.86297, 21.4255], [102.98846, 21.58936], [102.97965, 21.74076], [102.86077, 21.71213], [102.85637, 21.84501], [102.81894, 21.83888], [102.82115, 21.73667], [102.74189, 21.66713], [102.67145, 21.65894], [102.62301, 21.91447], [102.49092, 21.99002], [102.51734, 22.02676], [102.18712, 22.30403], [102.14099, 22.40092], [102.1245, 22.43372]]]]
24986           }
24987         }, {
24988           type: "Feature",
24989           properties: {
24990             iso1A2: "LB",
24991             iso1A3: "LBN",
24992             iso1N3: "422",
24993             wikidata: "Q822",
24994             nameEn: "Lebanon",
24995             aliases: ["RL"],
24996             groups: ["145", "142", "UN"],
24997             callingCodes: ["961"]
24998           },
24999           geometry: {
25000             type: "MultiPolygon",
25001             coordinates: [[[[35.94816, 33.47886], [35.94465, 33.52774], [36.05723, 33.57904], [35.9341, 33.6596], [36.06778, 33.82927], [36.14517, 33.85118], [36.3967, 33.83365], [36.38263, 33.86579], [36.28589, 33.91981], [36.41078, 34.05253], [36.50576, 34.05982], [36.5128, 34.09916], [36.62537, 34.20251], [36.59195, 34.2316], [36.58667, 34.27667], [36.60778, 34.31009], [36.56556, 34.31881], [36.53039, 34.3798], [36.55853, 34.41609], [36.46179, 34.46541], [36.4442, 34.50165], [36.34745, 34.5002], [36.3369, 34.52629], [36.39846, 34.55672], [36.41429, 34.61175], [36.45299, 34.59438], [36.46003, 34.6378], [36.42941, 34.62505], [36.35384, 34.65447], [36.35135, 34.68516], [36.32399, 34.69334], [36.29165, 34.62991], [35.98718, 34.64977], [35.97386, 34.63322], [35.48515, 34.70851], [34.78515, 33.20368], [35.10645, 33.09318], [35.1924, 33.08743], [35.31429, 33.10515], [35.35223, 33.05617], [35.43059, 33.06659], [35.448, 33.09264], [35.50272, 33.09056], [35.50335, 33.114], [35.52573, 33.11921], [35.54228, 33.19865], [35.5362, 33.23196], [35.54808, 33.236], [35.54544, 33.25513], [35.55555, 33.25844], [35.56523, 33.28969], [35.58326, 33.28381], [35.58502, 33.26653], [35.62283, 33.24226], [35.62019, 33.27278], [35.77477, 33.33609], [35.81324, 33.36354], [35.82577, 33.40479], [35.88668, 33.43183], [35.94816, 33.47886]]]]
25002           }
25003         }, {
25004           type: "Feature",
25005           properties: {
25006             iso1A2: "LC",
25007             iso1A3: "LCA",
25008             iso1N3: "662",
25009             wikidata: "Q760",
25010             nameEn: "St. Lucia",
25011             aliases: ["WL"],
25012             groups: ["029", "003", "419", "019", "UN"],
25013             driveSide: "left",
25014             roadSpeedUnit: "mph",
25015             callingCodes: ["1 758"]
25016           },
25017           geometry: {
25018             type: "MultiPolygon",
25019             coordinates: [[[[-59.95997, 14.20285], [-61.69315, 14.26451], [-59.94058, 12.34011], [-59.95997, 14.20285]]]]
25020           }
25021         }, {
25022           type: "Feature",
25023           properties: {
25024             iso1A2: "LI",
25025             iso1A3: "LIE",
25026             iso1N3: "438",
25027             wikidata: "Q347",
25028             nameEn: "Liechtenstein",
25029             aliases: ["FL"],
25030             groups: ["155", "150", "UN"],
25031             callingCodes: ["423"]
25032           },
25033           geometry: {
25034             type: "MultiPolygon",
25035             coordinates: [[[[9.60717, 47.06091], [9.61216, 47.07732], [9.63395, 47.08443], [9.62623, 47.14685], [9.56539, 47.17124], [9.58264, 47.20673], [9.56981, 47.21926], [9.55176, 47.22585], [9.56766, 47.24281], [9.53116, 47.27029], [9.52406, 47.24959], [9.50318, 47.22153], [9.4891, 47.19346], [9.48774, 47.17402], [9.51044, 47.13727], [9.52089, 47.10019], [9.51362, 47.08505], [9.47139, 47.06402], [9.47548, 47.05257], [9.54041, 47.06495], [9.55721, 47.04762], [9.60717, 47.06091]]]]
25036           }
25037         }, {
25038           type: "Feature",
25039           properties: {
25040             iso1A2: "LK",
25041             iso1A3: "LKA",
25042             iso1N3: "144",
25043             wikidata: "Q854",
25044             nameEn: "Sri Lanka",
25045             groups: ["034", "142", "UN"],
25046             driveSide: "left",
25047             callingCodes: ["94"]
25048           },
25049           geometry: {
25050             type: "MultiPolygon",
25051             coordinates: [[[[76.59015, 5.591], [85.15017, 5.21497], [80.48418, 10.20786], [79.42124, 9.80115], [79.50447, 8.91876], [76.59015, 5.591]]]]
25052           }
25053         }, {
25054           type: "Feature",
25055           properties: {
25056             iso1A2: "LR",
25057             iso1A3: "LBR",
25058             iso1N3: "430",
25059             wikidata: "Q1014",
25060             nameEn: "Liberia",
25061             groups: ["011", "202", "002", "UN"],
25062             callingCodes: ["231"]
25063           },
25064           geometry: {
25065             type: "MultiPolygon",
25066             coordinates: [[[[-8.47114, 7.55676], [-8.55874, 7.62525], [-8.55874, 7.70167], [-8.67814, 7.69428], [-8.72789, 7.51429], [-8.8448, 7.35149], [-8.85724, 7.26019], [-8.93435, 7.2824], [-9.09107, 7.1985], [-9.18311, 7.30461], [-9.20798, 7.38109], [-9.305, 7.42056], [-9.41943, 7.41809], [-9.48161, 7.37122], [-9.37465, 7.62032], [-9.35724, 7.74111], [-9.44928, 7.9284], [-9.41445, 8.02448], [-9.50898, 8.18455], [-9.47415, 8.35195], [-9.77763, 8.54633], [-10.05873, 8.42578], [-10.05375, 8.50697], [-10.14579, 8.52665], [-10.203, 8.47991], [-10.27575, 8.48711], [-10.30084, 8.30008], [-10.31635, 8.28554], [-10.29839, 8.21283], [-10.35227, 8.15223], [-10.45023, 8.15627], [-10.51554, 8.1393], [-10.57523, 8.04829], [-10.60492, 8.04072], [-10.60422, 7.7739], [-11.29417, 7.21576], [-11.4027, 6.97746], [-11.50429, 6.92704], [-12.15048, 6.15992], [-7.52774, 3.7105], [-7.53259, 4.35145], [-7.59349, 4.8909], [-7.53876, 4.94294], [-7.55369, 5.08667], [-7.48901, 5.14118], [-7.46165, 5.26256], [-7.36463, 5.32944], [-7.43428, 5.42355], [-7.37209, 5.61173], [-7.43926, 5.74787], [-7.43677, 5.84687], [-7.46165, 5.84934], [-7.48155, 5.80974], [-7.67309, 5.94337], [-7.70294, 5.90625], [-7.78254, 5.99037], [-7.79747, 6.07696], [-7.8497, 6.08932], [-7.83478, 6.20309], [-7.90692, 6.27728], [-8.00642, 6.31684], [-8.17557, 6.28222], [-8.3298, 6.36381], [-8.38453, 6.35887], [-8.45666, 6.49977], [-8.48652, 6.43797], [-8.59456, 6.50612], [-8.31736, 6.82837], [-8.29249, 7.1691], [-8.37458, 7.25794], [-8.41935, 7.51203], [-8.47114, 7.55676]]]]
25067           }
25068         }, {
25069           type: "Feature",
25070           properties: {
25071             iso1A2: "LS",
25072             iso1A3: "LSO",
25073             iso1N3: "426",
25074             wikidata: "Q1013",
25075             nameEn: "Lesotho",
25076             groups: ["018", "202", "002", "UN"],
25077             driveSide: "left",
25078             callingCodes: ["266"]
25079           },
25080           geometry: {
25081             type: "MultiPolygon",
25082             coordinates: [[[[29.33204, -29.45598], [29.44883, -29.3772], [29.40524, -29.21246], [28.68043, -28.58744], [28.65091, -28.57025], [28.40612, -28.6215], [28.30518, -28.69531], [28.2348, -28.69471], [28.1317, -28.7293], [28.02503, -28.85991], [27.98675, -28.8787], [27.9392, -28.84864], [27.88933, -28.88156], [27.8907, -28.91612], [27.75458, -28.89839], [27.55974, -29.18954], [27.5158, -29.2261], [27.54258, -29.25575], [27.48679, -29.29349], [27.45125, -29.29708], [27.47254, -29.31968], [27.4358, -29.33465], [27.33464, -29.48161], [27.01016, -29.65439], [27.09489, -29.72796], [27.22719, -30.00718], [27.29603, -30.05473], [27.32555, -30.14785], [27.40778, -30.14577], [27.37293, -30.19401], [27.36649, -30.27246], [27.38108, -30.33456], [27.45452, -30.32239], [27.56901, -30.42504], [27.56781, -30.44562], [27.62137, -30.50509], [27.6521, -30.51707], [27.67819, -30.53437], [27.69467, -30.55862], [27.74814, -30.60635], [28.12073, -30.68072], [28.2319, -30.28476], [28.399, -30.1592], [28.68627, -30.12885], [28.80222, -30.10579], [28.9338, -30.05072], [29.16548, -29.91706], [29.12553, -29.76266], [29.28545, -29.58456], [29.33204, -29.45598]]]]
25083           }
25084         }, {
25085           type: "Feature",
25086           properties: {
25087             iso1A2: "LT",
25088             iso1A3: "LTU",
25089             iso1N3: "440",
25090             wikidata: "Q37",
25091             nameEn: "Lithuania",
25092             groups: ["EU", "154", "150", "UN"],
25093             callingCodes: ["370"]
25094           },
25095           geometry: {
25096             type: "MultiPolygon",
25097             coordinates: [[[[24.89005, 56.46666], [24.83686, 56.41565], [24.70022, 56.40483], [24.57353, 56.31525], [24.58143, 56.29125], [24.42746, 56.26522], [24.32334, 56.30226], [24.13139, 56.24881], [24.02657, 56.3231], [23.75726, 56.37282], [23.49803, 56.34307], [23.40486, 56.37689], [23.31606, 56.3827], [23.17312, 56.36795], [23.09531, 56.30511], [22.96988, 56.41213], [22.83048, 56.367], [22.69354, 56.36284], [22.56441, 56.39305], [22.3361, 56.4016], [22.09728, 56.42851], [22.00548, 56.41508], [21.74558, 56.33181], [21.57888, 56.31406], [21.49736, 56.29106], [21.24644, 56.16917], [21.15016, 56.07818], [20.68447, 56.04073], [20.60454, 55.40986], [20.95181, 55.27994], [21.26425, 55.24456], [21.35465, 55.28427], [21.38446, 55.29348], [21.46766, 55.21115], [21.51095, 55.18507], [21.55605, 55.20311], [21.64954, 55.1791], [21.85521, 55.09493], [21.96505, 55.07353], [21.99543, 55.08691], [22.03984, 55.07888], [22.02582, 55.05078], [22.06087, 55.02935], [22.11697, 55.02131], [22.14267, 55.05345], [22.31562, 55.0655], [22.47688, 55.04408], [22.58907, 55.07085], [22.60075, 55.01863], [22.65451, 54.97037], [22.68723, 54.9811], [22.76422, 54.92521], [22.85083, 54.88711], [22.87317, 54.79492], [22.73631, 54.72952], [22.73397, 54.66604], [22.75467, 54.6483], [22.74225, 54.64339], [22.7522, 54.63525], [22.68021, 54.58486], [22.71293, 54.56454], [22.67788, 54.532], [22.70208, 54.45312], [22.7253, 54.41732], [22.79705, 54.36264], [22.83756, 54.40827], [23.00584, 54.38514], [22.99649, 54.35927], [23.05726, 54.34565], [23.04323, 54.31567], [23.104, 54.29794], [23.13905, 54.31567], [23.15526, 54.31076], [23.15938, 54.29894], [23.24656, 54.25701], [23.3494, 54.25155], [23.39525, 54.21672], [23.42418, 54.17911], [23.45223, 54.17775], [23.49196, 54.14764], [23.52702, 54.04622], [23.48261, 53.98855], [23.51284, 53.95052], [23.61677, 53.92691], [23.71726, 53.93379], [23.80543, 53.89558], [23.81309, 53.94205], [23.95098, 53.9613], [23.98837, 53.92554], [24.19638, 53.96405], [24.34128, 53.90076], [24.44411, 53.90076], [24.62275, 54.00217], [24.69652, 54.01901], [24.69185, 53.96543], [24.74279, 53.96663], [24.85311, 54.02862], [24.77131, 54.11091], [24.96894, 54.17589], [24.991, 54.14241], [25.0728, 54.13419], [25.19199, 54.219], [25.22705, 54.26271], [25.35559, 54.26544], [25.509, 54.30267], [25.56823, 54.25212], [25.51452, 54.17799], [25.54724, 54.14925], [25.64875, 54.1259], [25.71084, 54.16704], [25.78563, 54.15747], [25.78553, 54.23327], [25.68513, 54.31727], [25.55425, 54.31591], [25.5376, 54.33158], [25.63371, 54.42075], [25.62203, 54.4656], [25.64813, 54.48704], [25.68045, 54.5321], [25.75977, 54.57252], [25.74122, 54.80108], [25.89462, 54.93438], [25.99129, 54.95705], [26.05907, 54.94631], [26.13386, 54.98924], [26.20397, 54.99729], [26.26941, 55.08032], [26.23202, 55.10439], [26.30628, 55.12536], [26.35121, 55.1525], [26.46249, 55.12814], [26.51481, 55.16051], [26.54753, 55.14181], [26.69243, 55.16718], [26.68075, 55.19787], [26.72983, 55.21788], [26.73017, 55.24226], [26.835, 55.28182], [26.83266, 55.30444], [26.80929, 55.31642], [26.6714, 55.33902], [26.5709, 55.32572], [26.44937, 55.34832], [26.5522, 55.40277], [26.55094, 55.5093], [26.63167, 55.57887], [26.63231, 55.67968], [26.58248, 55.6754], [26.46661, 55.70375], [26.39561, 55.71156], [26.18509, 55.86813], [26.03815, 55.95884], [25.90047, 56.0013], [25.85893, 56.00188], [25.81773, 56.05444], [25.69246, 56.08892], [25.68588, 56.14725], [25.53621, 56.16663], [25.39751, 56.15707], [25.23099, 56.19147], [25.09325, 56.1878], [25.05762, 56.26742], [24.89005, 56.46666]]]]
25098           }
25099         }, {
25100           type: "Feature",
25101           properties: {
25102             iso1A2: "LU",
25103             iso1A3: "LUX",
25104             iso1N3: "442",
25105             wikidata: "Q32",
25106             nameEn: "Luxembourg",
25107             groups: ["EU", "155", "150", "UN"],
25108             callingCodes: ["352"]
25109           },
25110           geometry: {
25111             type: "MultiPolygon",
25112             coordinates: [[[[6.1379, 50.12964], [6.1137, 50.13668], [6.12028, 50.16374], [6.08577, 50.17246], [6.06406, 50.15344], [6.03093, 50.16362], [6.02488, 50.18283], [5.96453, 50.17259], [5.95929, 50.13295], [5.89488, 50.11476], [5.8857, 50.07824], [5.85474, 50.06342], [5.86904, 50.04614], [5.8551, 50.02683], [5.81866, 50.01286], [5.82331, 49.99662], [5.83968, 49.9892], [5.83467, 49.97823], [5.81163, 49.97142], [5.80833, 49.96451], [5.77291, 49.96056], [5.77314, 49.93646], [5.73621, 49.89796], [5.78415, 49.87922], [5.75269, 49.8711], [5.75861, 49.85631], [5.74567, 49.85368], [5.75884, 49.84811], [5.74953, 49.84709], [5.74975, 49.83933], [5.74076, 49.83823], [5.7404, 49.83452], [5.74844, 49.82435], [5.74364, 49.82058], [5.74953, 49.81428], [5.75409, 49.79239], [5.78871, 49.7962], [5.82245, 49.75048], [5.83149, 49.74729], [5.82562, 49.72395], [5.84193, 49.72161], [5.86503, 49.72739], [5.88677, 49.70951], [5.86527, 49.69291], [5.86175, 49.67862], [5.9069, 49.66377], [5.90164, 49.6511], [5.90599, 49.63853], [5.88552, 49.63507], [5.88393, 49.62802], [5.87609, 49.62047], [5.8762, 49.60898], [5.84826, 49.5969], [5.84971, 49.58674], [5.86986, 49.58756], [5.87256, 49.57539], [5.8424, 49.56082], [5.84692, 49.55663], [5.84143, 49.5533], [5.81838, 49.54777], [5.80871, 49.5425], [5.81664, 49.53775], [5.83648, 49.5425], [5.84466, 49.53027], [5.83467, 49.52717], [5.83389, 49.52152], [5.86571, 49.50015], [5.94128, 49.50034], [5.94224, 49.49608], [5.96876, 49.49053], [5.97693, 49.45513], [6.02648, 49.45451], [6.02743, 49.44845], [6.04176, 49.44801], [6.05553, 49.46663], [6.07887, 49.46399], [6.08373, 49.45594], [6.10072, 49.45268], [6.09845, 49.46351], [6.10325, 49.4707], [6.12346, 49.4735], [6.12814, 49.49365], [6.14321, 49.48796], [6.16115, 49.49297], [6.15366, 49.50226], [6.17386, 49.50934], [6.19543, 49.50536], [6.2409, 49.51408], [6.25029, 49.50609], [6.27875, 49.503], [6.28818, 49.48465], [6.3687, 49.4593], [6.36778, 49.46937], [6.36907, 49.48931], [6.36788, 49.50377], [6.35666, 49.52931], [6.38072, 49.55171], [6.38228, 49.55855], [6.35825, 49.57053], [6.36676, 49.57813], [6.38024, 49.57593], [6.38342, 49.5799], [6.37464, 49.58886], [6.385, 49.59946], [6.39822, 49.60081], [6.41861, 49.61723], [6.4413, 49.65722], [6.43768, 49.66021], [6.42726, 49.66078], [6.42937, 49.66857], [6.44654, 49.67799], [6.46048, 49.69092], [6.48014, 49.69767], [6.49785, 49.71118], [6.50647, 49.71353], [6.5042, 49.71808], [6.49694, 49.72205], [6.49535, 49.72645], [6.50261, 49.72718], [6.51397, 49.72058], [6.51805, 49.72425], [6.50193, 49.73291], [6.50174, 49.75292], [6.51646, 49.75961], [6.51828, 49.76855], [6.51056, 49.77515], [6.51669, 49.78336], [6.50534, 49.78952], [6.52169, 49.79787], [6.53122, 49.80666], [6.52121, 49.81338], [6.51215, 49.80124], [6.50647, 49.80916], [6.48718, 49.81267], [6.47111, 49.82263], [6.45425, 49.81164], [6.44131, 49.81443], [6.42905, 49.81091], [6.42521, 49.81591], [6.40022, 49.82029], [6.36576, 49.85032], [6.34267, 49.84974], [6.33585, 49.83785], [6.32098, 49.83728], [6.32303, 49.85133], [6.30963, 49.87021], [6.29692, 49.86685], [6.28874, 49.87592], [6.26146, 49.88203], [6.23496, 49.89972], [6.22926, 49.92096], [6.21882, 49.92403], [6.22608, 49.929], [6.22094, 49.94955], [6.19856, 49.95053], [6.19089, 49.96991], [6.18045, 49.96611], [6.18554, 49.95622], [6.17872, 49.9537], [6.16466, 49.97086], [6.1701, 49.98518], [6.14147, 49.99563], [6.14948, 50.00908], [6.13806, 50.01056], [6.1295, 50.01849], [6.13273, 50.02019], [6.13794, 50.01466], [6.14666, 50.02207], [6.13044, 50.02929], [6.13458, 50.04141], [6.11274, 50.05916], [6.12055, 50.09171], [6.1379, 50.12964]]]]
25113           }
25114         }, {
25115           type: "Feature",
25116           properties: {
25117             iso1A2: "LV",
25118             iso1A3: "LVA",
25119             iso1N3: "428",
25120             wikidata: "Q211",
25121             nameEn: "Latvia",
25122             groups: ["EU", "154", "150", "UN"],
25123             callingCodes: ["371"]
25124           },
25125           geometry: {
25126             type: "MultiPolygon",
25127             coordinates: [[[[27.34698, 57.52242], [26.90364, 57.62823], [26.54675, 57.51813], [26.46527, 57.56885], [26.29253, 57.59244], [26.1866, 57.6849], [26.2029, 57.7206], [26.08098, 57.76619], [26.0543, 57.76105], [26.03332, 57.7718], [26.02415, 57.76865], [26.02069, 57.77169], [26.0266, 57.77441], [26.027, 57.78158], [26.02456, 57.78342], [26.0324, 57.79037], [26.05949, 57.84744], [25.73499, 57.90193], [25.29581, 58.08288], [25.28237, 57.98539], [25.19484, 58.0831], [24.3579, 57.87471], [24.26221, 57.91787], [23.20055, 57.56697], [22.80496, 57.87798], [19.84909, 57.57876], [19.64795, 57.06466], [20.68447, 56.04073], [21.15016, 56.07818], [21.24644, 56.16917], [21.49736, 56.29106], [21.57888, 56.31406], [21.74558, 56.33181], [22.00548, 56.41508], [22.09728, 56.42851], [22.3361, 56.4016], [22.56441, 56.39305], [22.69354, 56.36284], [22.83048, 56.367], [22.96988, 56.41213], [23.09531, 56.30511], [23.17312, 56.36795], [23.31606, 56.3827], [23.40486, 56.37689], [23.49803, 56.34307], [23.75726, 56.37282], [24.02657, 56.3231], [24.13139, 56.24881], [24.32334, 56.30226], [24.42746, 56.26522], [24.58143, 56.29125], [24.57353, 56.31525], [24.70022, 56.40483], [24.83686, 56.41565], [24.89005, 56.46666], [25.05762, 56.26742], [25.09325, 56.1878], [25.23099, 56.19147], [25.39751, 56.15707], [25.53621, 56.16663], [25.68588, 56.14725], [25.69246, 56.08892], [25.81773, 56.05444], [25.85893, 56.00188], [25.90047, 56.0013], [26.03815, 55.95884], [26.18509, 55.86813], [26.39561, 55.71156], [26.46661, 55.70375], [26.58248, 55.6754], [26.63231, 55.67968], [26.64888, 55.70515], [26.71802, 55.70645], [26.76872, 55.67658], [26.87448, 55.7172], [26.97153, 55.8102], [27.1559, 55.85032], [27.27804, 55.78299], [27.3541, 55.8089], [27.61683, 55.78558], [27.63065, 55.89687], [27.97865, 56.11849], [28.15217, 56.16964], [28.23716, 56.27588], [28.16599, 56.37806], [28.19057, 56.44637], [28.10069, 56.524], [28.13526, 56.57989], [28.04768, 56.59004], [27.86101, 56.88204], [27.66511, 56.83921], [27.86101, 57.29402], [27.52453, 57.42826], [27.56832, 57.53728], [27.34698, 57.52242]]]]
25128           }
25129         }, {
25130           type: "Feature",
25131           properties: {
25132             iso1A2: "LY",
25133             iso1A3: "LBY",
25134             iso1N3: "434",
25135             wikidata: "Q1016",
25136             nameEn: "Libya",
25137             groups: ["015", "002", "UN"],
25138             callingCodes: ["218"]
25139           },
25140           geometry: {
25141             type: "MultiPolygon",
25142             coordinates: [[[[26.92891, 33.39516], [11.58941, 33.36891], [11.55852, 33.1409], [11.51549, 33.09826], [11.46037, 32.6307], [11.57828, 32.48013], [11.53898, 32.4138], [11.04234, 32.2145], [10.7315, 31.97235], [10.62788, 31.96629], [10.48497, 31.72956], [10.31364, 31.72648], [10.12239, 31.42098], [10.29516, 30.90337], [9.88152, 30.34074], [9.76848, 30.34366], [9.55544, 30.23971], [9.3876, 30.16738], [9.78136, 29.40961], [9.89569, 26.57696], [9.51696, 26.39148], [9.38834, 26.19288], [10.03146, 25.35635], [10.02432, 24.98124], [10.33159, 24.5465], [10.85323, 24.5595], [11.41061, 24.21456], [11.62498, 24.26669], [11.96886, 23.51735], [13.5631, 23.16574], [14.22918, 22.61719], [14.99751, 23.00539], [15.99566, 23.49639], [23.99539, 19.49944], [23.99715, 20.00038], [24.99794, 19.99661], [24.99885, 21.99535], [24.99968, 29.24574], [24.71117, 30.17441], [25.01077, 30.73861], [24.8458, 31.39877], [26.92891, 33.39516]]]]
25143           }
25144         }, {
25145           type: "Feature",
25146           properties: {
25147             iso1A2: "MA",
25148             iso1A3: "MAR",
25149             iso1N3: "504",
25150             wikidata: "Q1028",
25151             nameEn: "Morocco",
25152             groups: ["015", "002", "UN"],
25153             callingCodes: ["212"]
25154           },
25155           geometry: {
25156             type: "MultiPolygon",
25157             coordinates: [[[[-2.27707, 35.35051], [-5.10878, 36.05227], [-7.2725, 35.73269], [-14.43883, 27.02969], [-17.27295, 21.93519], [-17.21511, 21.34226], [-17.02707, 21.34022], [-16.9978, 21.36239], [-16.44269, 21.39745], [-14.78487, 21.36587], [-14.47329, 21.63839], [-14.48112, 22.00886], [-14.1291, 22.41636], [-14.10361, 22.75501], [-13.75627, 23.77231], [-13.00628, 24.01923], [-12.92147, 24.39502], [-12.12281, 25.13682], [-12.06001, 26.04442], [-11.62052, 26.05229], [-11.38635, 26.611], [-11.23622, 26.72023], [-11.35695, 26.8505], [-10.68417, 26.90984], [-9.81998, 26.71379], [-9.56957, 26.90042], [-9.08698, 26.98639], [-8.71787, 26.9898], [-8.77527, 27.66663], [-8.66879, 27.6666], [-8.6715, 28.71194], [-7.61585, 29.36252], [-6.95824, 29.50924], [-6.78351, 29.44634], [-6.69965, 29.51623], [-5.75616, 29.61407], [-5.72121, 29.52322], [-5.58831, 29.48103], [-5.21671, 29.95253], [-4.6058, 30.28343], [-4.31774, 30.53229], [-3.64735, 30.67539], [-3.65418, 30.85566], [-3.54944, 31.0503], [-3.77103, 31.14984], [-3.77647, 31.31912], [-3.66386, 31.39202], [-3.66314, 31.6339], [-2.82784, 31.79459], [-2.93873, 32.06557], [-2.46166, 32.16603], [-1.22829, 32.07832], [-1.15735, 32.12096], [-1.24453, 32.1917], [-1.24998, 32.32993], [-0.9912, 32.52467], [-1.37794, 32.73628], [-1.54244, 32.95499], [-1.46249, 33.0499], [-1.67067, 33.27084], [-1.59508, 33.59929], [-1.73494, 33.71721], [-1.64666, 34.10405], [-1.78042, 34.39018], [-1.69788, 34.48056], [-1.84569, 34.61907], [-1.73707, 34.74226], [-1.97469, 34.886], [-1.97833, 34.93218], [-2.04734, 34.93218], [-2.21445, 35.04378], [-2.21248, 35.08532], [-2.27707, 35.35051]], [[-2.91909, 35.33927], [-2.92272, 35.27509], [-2.93893, 35.26737], [-2.95065, 35.26576], [-2.95431, 35.2728], [-2.96516, 35.27967], [-2.96826, 35.28296], [-2.96507, 35.28801], [-2.97035, 35.28852], [-2.96978, 35.29459], [-2.96648, 35.30475], [-2.96038, 35.31609], [-2.91909, 35.33927]], [[-3.90602, 35.21494], [-3.89343, 35.22728], [-3.88372, 35.20767], [-3.90602, 35.21494]], [[-4.30191, 35.17419], [-4.29436, 35.17149], [-4.30112, 35.17058], [-4.30191, 35.17419]], [[-2.40316, 35.16893], [-2.45965, 35.16527], [-2.43262, 35.20652], [-2.40316, 35.16893]], [[-5.38491, 35.92591], [-5.21179, 35.90091], [-5.34379, 35.8711], [-5.35844, 35.87375], [-5.37338, 35.88417], [-5.38491, 35.92591]]]]
25158           }
25159         }, {
25160           type: "Feature",
25161           properties: {
25162             iso1A2: "MC",
25163             iso1A3: "MCO",
25164             iso1N3: "492",
25165             wikidata: "Q235",
25166             nameEn: "Monaco",
25167             groups: ["155", "150", "UN"],
25168             callingCodes: ["377"]
25169           },
25170           geometry: {
25171             type: "MultiPolygon",
25172             coordinates: [[[[7.47823, 43.73341], [7.4379, 43.74963], [7.4389, 43.75151], [7.43708, 43.75197], [7.43624, 43.75014], [7.43013, 43.74895], [7.42809, 43.74396], [7.42443, 43.74087], [7.42299, 43.74176], [7.42062, 43.73977], [7.41233, 43.73439], [7.41298, 43.73311], [7.41291, 43.73168], [7.41113, 43.73156], [7.40903, 43.7296], [7.42422, 43.72209], [7.47823, 43.73341]]]]
25173           }
25174         }, {
25175           type: "Feature",
25176           properties: {
25177             iso1A2: "MD",
25178             iso1A3: "MDA",
25179             iso1N3: "498",
25180             wikidata: "Q217",
25181             nameEn: "Moldova",
25182             groups: ["151", "150", "UN"],
25183             callingCodes: ["373"]
25184           },
25185           geometry: {
25186             type: "MultiPolygon",
25187             coordinates: [[[[27.74422, 48.45926], [27.6658, 48.44034], [27.59027, 48.46311], [27.5889, 48.49224], [27.46942, 48.454], [27.44333, 48.41209], [27.37741, 48.41026], [27.37604, 48.44398], [27.32159, 48.4434], [27.27855, 48.37534], [27.13434, 48.37288], [27.08078, 48.43214], [27.0231, 48.42485], [27.03821, 48.37653], [26.93384, 48.36558], [26.85556, 48.41095], [26.71274, 48.40388], [26.82809, 48.31629], [26.79239, 48.29071], [26.6839, 48.35828], [26.62823, 48.25804], [26.81161, 48.25049], [26.87708, 48.19919], [26.94265, 48.1969], [26.98042, 48.15752], [26.96119, 48.13003], [27.04118, 48.12522], [27.02985, 48.09083], [27.15622, 47.98538], [27.1618, 47.92391], [27.29069, 47.73722], [27.25519, 47.71366], [27.32202, 47.64009], [27.3979, 47.59473], [27.47942, 47.48113], [27.55731, 47.46637], [27.60263, 47.32507], [27.68706, 47.28962], [27.73172, 47.29248], [27.81892, 47.1381], [28.09095, 46.97621], [28.12173, 46.82283], [28.24808, 46.64305], [28.22281, 46.50481], [28.25769, 46.43334], [28.18902, 46.35283], [28.19864, 46.31869], [28.10937, 46.22852], [28.13684, 46.18099], [28.08612, 46.01105], [28.13111, 45.92819], [28.16568, 45.6421], [28.08927, 45.6051], [28.18741, 45.47358], [28.21139, 45.46895], [28.30201, 45.54744], [28.41836, 45.51715], [28.43072, 45.48538], [28.51449, 45.49982], [28.49252, 45.56716], [28.54196, 45.58062], [28.51587, 45.6613], [28.47879, 45.66994], [28.52823, 45.73803], [28.70401, 45.78019], [28.69852, 45.81753], [28.78503, 45.83475], [28.74383, 45.96664], [28.98004, 46.00385], [29.00613, 46.04962], [28.94643, 46.09176], [29.06656, 46.19716], [28.94953, 46.25852], [28.98478, 46.31803], [29.004, 46.31495], [28.9306, 46.45699], [29.01241, 46.46177], [29.02409, 46.49582], [29.23547, 46.55435], [29.24886, 46.37912], [29.35357, 46.49505], [29.49914, 46.45889], [29.5939, 46.35472], [29.6763, 46.36041], [29.66359, 46.4215], [29.74496, 46.45605], [29.88329, 46.35851], [29.94114, 46.40114], [30.09103, 46.38694], [30.16794, 46.40967], [30.02511, 46.45132], [29.88916, 46.54302], [29.94409, 46.56002], [29.9743, 46.75325], [29.94522, 46.80055], [29.98814, 46.82358], [29.87405, 46.88199], [29.75458, 46.8604], [29.72986, 46.92234], [29.57056, 46.94766], [29.62137, 47.05069], [29.61038, 47.09932], [29.53044, 47.07851], [29.49732, 47.12878], [29.57696, 47.13581], [29.54996, 47.24962], [29.59665, 47.25521], [29.5733, 47.36508], [29.48678, 47.36043], [29.47854, 47.30366], [29.39889, 47.30179], [29.3261, 47.44664], [29.18603, 47.43387], [29.11743, 47.55001], [29.22414, 47.60012], [29.22242, 47.73607], [29.27255, 47.79953], [29.20663, 47.80367], [29.27804, 47.88893], [29.19839, 47.89261], [29.1723, 47.99013], [28.9306, 47.96255], [28.8414, 48.03392], [28.85232, 48.12506], [28.69896, 48.13106], [28.53921, 48.17453], [28.48428, 48.0737], [28.42454, 48.12047], [28.43701, 48.15832], [28.38712, 48.17567], [28.34009, 48.13147], [28.30609, 48.14018], [28.30586, 48.1597], [28.34912, 48.1787], [28.36996, 48.20543], [28.35519, 48.24957], [28.32508, 48.23384], [28.2856, 48.23202], [28.19314, 48.20749], [28.17666, 48.25963], [28.07504, 48.23494], [28.09873, 48.3124], [28.04527, 48.32661], [27.95883, 48.32368], [27.88391, 48.36699], [27.87533, 48.4037], [27.81902, 48.41874], [27.79225, 48.44244], [27.74422, 48.45926]]]]
25188           }
25189         }, {
25190           type: "Feature",
25191           properties: {
25192             iso1A2: "ME",
25193             iso1A3: "MNE",
25194             iso1N3: "499",
25195             wikidata: "Q236",
25196             nameEn: "Montenegro",
25197             groups: ["039", "150", "UN"],
25198             callingCodes: ["382"]
25199           },
25200           geometry: {
25201             type: "MultiPolygon",
25202             coordinates: [[[[19.22807, 43.5264], [19.15685, 43.53943], [19.13933, 43.5282], [19.04934, 43.50384], [19.01078, 43.55806], [18.91379, 43.50299], [18.95469, 43.49367], [18.96053, 43.45042], [19.01078, 43.43854], [19.04071, 43.397], [19.08673, 43.31453], [19.08206, 43.29668], [19.04233, 43.30008], [19.00844, 43.24988], [18.95001, 43.29327], [18.95819, 43.32899], [18.90911, 43.36383], [18.83912, 43.34795], [18.84794, 43.33735], [18.85342, 43.32426], [18.76538, 43.29838], [18.6976, 43.25243], [18.71747, 43.2286], [18.66605, 43.2056], [18.64735, 43.14766], [18.66254, 43.03928], [18.52232, 43.01451], [18.49076, 42.95553], [18.49661, 42.89306], [18.4935, 42.86433], [18.47633, 42.85829], [18.45921, 42.81682], [18.47324, 42.74992], [18.56789, 42.72074], [18.55221, 42.69045], [18.54603, 42.69171], [18.54841, 42.68328], [18.57373, 42.64429], [18.52232, 42.62279], [18.55504, 42.58409], [18.53751, 42.57376], [18.49778, 42.58409], [18.43735, 42.55921], [18.44307, 42.51077], [18.43588, 42.48556], [18.52152, 42.42302], [18.54128, 42.39171], [18.45131, 42.21682], [19.26406, 41.74971], [19.37597, 41.84849], [19.37451, 41.8842], [19.33812, 41.90669], [19.34601, 41.95675], [19.37691, 41.96977], [19.36867, 42.02564], [19.37548, 42.06835], [19.40687, 42.10024], [19.28623, 42.17745], [19.42, 42.33019], [19.42352, 42.36546], [19.4836, 42.40831], [19.65972, 42.62774], [19.73244, 42.66299], [19.77375, 42.58517], [19.74731, 42.57422], [19.76549, 42.50237], [19.82333, 42.46581], [19.9324, 42.51699], [20.00842, 42.5109], [20.01834, 42.54622], [20.07761, 42.55582], [20.0969, 42.65559], [20.02915, 42.71147], [20.02088, 42.74789], [20.04898, 42.77701], [20.2539, 42.76245], [20.27869, 42.81945], [20.35692, 42.8335], [20.34528, 42.90676], [20.16415, 42.97177], [20.14896, 42.99058], [20.12325, 42.96237], [20.05431, 42.99571], [20.04729, 43.02732], [19.98887, 43.0538], [19.96549, 43.11098], [19.92576, 43.08539], [19.79255, 43.11951], [19.76918, 43.16044], [19.64063, 43.19027], [19.62661, 43.2286], [19.54598, 43.25158], [19.52962, 43.31623], [19.48171, 43.32644], [19.44315, 43.38846], [19.22229, 43.47926], [19.22807, 43.5264]]]]
25203           }
25204         }, {
25205           type: "Feature",
25206           properties: {
25207             iso1A2: "MF",
25208             iso1A3: "MAF",
25209             iso1N3: "663",
25210             wikidata: "Q126125",
25211             nameEn: "Saint-Martin",
25212             country: "FR",
25213             groups: ["Q3320166", "EU", "029", "003", "419", "019", "UN"],
25214             callingCodes: ["590"]
25215           },
25216           geometry: {
25217             type: "MultiPolygon",
25218             coordinates: [[[[-62.93924, 18.02904], [-62.62718, 18.26185], [-63.35989, 18.06012], [-63.33064, 17.9615], [-63.13502, 18.05445], [-63.11042, 18.05339], [-63.09686, 18.04608], [-63.07759, 18.04943], [-63.0579, 18.06614], [-63.04039, 18.05619], [-63.02323, 18.05757], [-62.93924, 18.02904]]]]
25219           }
25220         }, {
25221           type: "Feature",
25222           properties: {
25223             iso1A2: "MG",
25224             iso1A3: "MDG",
25225             iso1N3: "450",
25226             wikidata: "Q1019",
25227             nameEn: "Madagascar",
25228             aliases: ["RM"],
25229             groups: ["014", "202", "002", "UN"],
25230             callingCodes: ["261"]
25231           },
25232           geometry: {
25233             type: "MultiPolygon",
25234             coordinates: [[[[51.93891, -10.85085], [45.84651, -12.77177], [42.14681, -19.63341], [45.80092, -33.00974], [51.93891, -10.85085]]]]
25235           }
25236         }, {
25237           type: "Feature",
25238           properties: {
25239             iso1A2: "MH",
25240             iso1A3: "MHL",
25241             iso1N3: "584",
25242             wikidata: "Q709",
25243             nameEn: "Marshall Islands",
25244             groups: ["057", "009", "UN"],
25245             roadSpeedUnit: "mph",
25246             callingCodes: ["692"]
25247           },
25248           geometry: {
25249             type: "MultiPolygon",
25250             coordinates: [[[[169, 3.9], [173.53711, 5.70687], [169.29099, 15.77133], [159.04653, 10.59067], [169, 3.9]]]]
25251           }
25252         }, {
25253           type: "Feature",
25254           properties: {
25255             iso1A2: "MK",
25256             iso1A3: "MKD",
25257             iso1N3: "807",
25258             wikidata: "Q221",
25259             nameEn: "North Macedonia",
25260             groups: ["039", "150", "UN"],
25261             callingCodes: ["389"]
25262           },
25263           geometry: {
25264             type: "MultiPolygon",
25265             coordinates: [[[[22.34773, 42.31725], [22.29275, 42.34913], [22.29605, 42.37477], [22.16384, 42.32103], [22.02908, 42.29848], [21.94405, 42.34669], [21.91595, 42.30392], [21.84654, 42.3247], [21.77176, 42.2648], [21.70111, 42.23789], [21.58992, 42.25915], [21.52145, 42.24465], [21.50823, 42.27156], [21.43882, 42.2789], [21.43882, 42.23609], [21.38428, 42.24465], [21.30496, 42.1418], [21.29913, 42.13954], [21.31983, 42.10993], [21.22728, 42.08909], [21.16614, 42.19815], [21.11491, 42.20794], [20.75464, 42.05229], [20.76786, 41.91839], [20.68523, 41.85318], [20.59524, 41.8818], [20.55976, 41.87068], [20.57144, 41.7897], [20.53405, 41.78099], [20.51301, 41.72433], [20.52937, 41.69292], [20.51769, 41.65975], [20.55508, 41.58113], [20.52103, 41.56473], [20.45809, 41.5549], [20.45331, 41.51436], [20.49039, 41.49277], [20.51301, 41.442], [20.55976, 41.4087], [20.52119, 41.34381], [20.49432, 41.33679], [20.51068, 41.2323], [20.59715, 41.13644], [20.58546, 41.11179], [20.59832, 41.09066], [20.63454, 41.0889], [20.65558, 41.08009], [20.71634, 40.91781], [20.73504, 40.9081], [20.81567, 40.89662], [20.83671, 40.92752], [20.94305, 40.92399], [20.97693, 40.90103], [20.97887, 40.85475], [21.15262, 40.85546], [21.21105, 40.8855], [21.25779, 40.86165], [21.35595, 40.87578], [21.41555, 40.9173], [21.53007, 40.90759], [21.57448, 40.86076], [21.69601, 40.9429], [21.7556, 40.92525], [21.91102, 41.04786], [21.90869, 41.09191], [22.06527, 41.15617], [22.1424, 41.12449], [22.17629, 41.15969], [22.26744, 41.16409], [22.42285, 41.11921], [22.5549, 41.13065], [22.58295, 41.11568], [22.62852, 41.14385], [22.65306, 41.18168], [22.71266, 41.13945], [22.74538, 41.16321], [22.76408, 41.32225], [22.81199, 41.3398], [22.93334, 41.34104], [22.96331, 41.35782], [22.95513, 41.63265], [23.03342, 41.71034], [23.01239, 41.76527], [22.96682, 41.77137], [22.90254, 41.87587], [22.86749, 42.02275], [22.67701, 42.06614], [22.51224, 42.15457], [22.50289, 42.19527], [22.47251, 42.20393], [22.38136, 42.30339], [22.34773, 42.31725]]]]
25266           }
25267         }, {
25268           type: "Feature",
25269           properties: {
25270             iso1A2: "ML",
25271             iso1A3: "MLI",
25272             iso1N3: "466",
25273             wikidata: "Q912",
25274             nameEn: "Mali",
25275             groups: ["011", "202", "002", "UN"],
25276             callingCodes: ["223"]
25277           },
25278           geometry: {
25279             type: "MultiPolygon",
25280             coordinates: [[[[-4.83423, 24.99935], [-6.57191, 25.0002], [-5.60725, 16.49919], [-5.33435, 16.33354], [-5.50165, 15.50061], [-9.32979, 15.50032], [-9.31106, 15.69412], [-9.33314, 15.7044], [-9.44673, 15.60553], [-9.40447, 15.4396], [-10.71721, 15.4223], [-10.90932, 15.11001], [-11.43483, 15.62339], [-11.70705, 15.51558], [-11.94903, 14.76143], [-12.23936, 14.76324], [-11.93043, 13.84505], [-12.06897, 13.71049], [-11.83345, 13.33333], [-11.63025, 13.39174], [-11.39935, 12.97808], [-11.37536, 12.40788], [-11.50006, 12.17826], [-11.24136, 12.01286], [-10.99758, 12.24634], [-10.80355, 12.1053], [-10.71897, 11.91552], [-10.30604, 12.24634], [-9.714, 12.0226], [-9.63938, 12.18312], [-9.32097, 12.29009], [-9.38067, 12.48446], [-9.13689, 12.50875], [-8.94784, 12.34842], [-8.80854, 11.66715], [-8.40058, 11.37466], [-8.66923, 10.99397], [-8.35083, 11.06234], [-8.2667, 10.91762], [-8.32614, 10.69273], [-8.22711, 10.41722], [-8.10207, 10.44649], [-7.9578, 10.2703], [-7.97971, 10.17117], [-7.92107, 10.15577], [-7.63048, 10.46334], [-7.54462, 10.40921], [-7.52261, 10.4655], [-7.44555, 10.44602], [-7.3707, 10.24677], [-7.13331, 10.24877], [-7.0603, 10.14711], [-7.00966, 10.15794], [-6.97444, 10.21644], [-7.01186, 10.25111], [-6.93921, 10.35291], [-6.68164, 10.35074], [-6.63541, 10.66893], [-6.52974, 10.59104], [-6.42847, 10.5694], [-6.40646, 10.69922], [-6.325, 10.68624], [-6.24795, 10.74248], [-6.1731, 10.46983], [-6.18851, 10.24244], [-5.99478, 10.19694], [-5.78124, 10.43952], [-5.65135, 10.46767], [-5.51058, 10.43177], [-5.46643, 10.56074], [-5.47083, 10.75329], [-5.41579, 10.84628], [-5.49284, 11.07538], [-5.32994, 11.13371], [-5.32553, 11.21578], [-5.25949, 11.24816], [-5.25509, 11.36905], [-5.20665, 11.43811], [-5.22867, 11.60421], [-5.29251, 11.61715], [-5.26389, 11.75728], [-5.40258, 11.8327], [-5.26389, 11.84778], [-5.07897, 11.97918], [-4.72893, 12.01579], [-4.70692, 12.06746], [-4.62987, 12.06531], [-4.62546, 12.13204], [-4.54841, 12.1385], [-4.57703, 12.19875], [-4.41412, 12.31922], [-4.47356, 12.71252], [-4.238, 12.71467], [-4.21819, 12.95722], [-4.34477, 13.12927], [-3.96501, 13.49778], [-3.90558, 13.44375], [-3.96282, 13.38164], [-3.7911, 13.36665], [-3.54454, 13.1781], [-3.4313, 13.1588], [-3.43507, 13.27272], [-3.23599, 13.29035], [-3.28396, 13.5422], [-3.26407, 13.70699], [-2.88189, 13.64921], [-2.90831, 13.81174], [-2.84667, 14.05532], [-2.66175, 14.14713], [-2.47587, 14.29671], [-2.10223, 14.14878], [-1.9992, 14.19011], [-1.97945, 14.47709], [-1.68083, 14.50023], [-1.32166, 14.72774], [-1.05875, 14.7921], [-0.72004, 15.08655], [-0.24673, 15.07805], [0.06588, 14.96961], [0.23859, 15.00135], [0.72632, 14.95898], [0.96711, 14.98275], [1.31275, 15.27978], [3.01806, 15.34571], [3.03134, 15.42221], [3.50368, 15.35934], [4.19893, 16.39923], [4.21787, 17.00118], [4.26762, 17.00432], [4.26651, 19.14224], [3.36082, 18.9745], [3.12501, 19.1366], [3.24648, 19.81703], [1.20992, 20.73533], [1.15698, 21.12843], [-4.83423, 24.99935]]]]
25281           }
25282         }, {
25283           type: "Feature",
25284           properties: {
25285             iso1A2: "MM",
25286             iso1A3: "MMR",
25287             iso1N3: "104",
25288             wikidata: "Q836",
25289             nameEn: "Myanmar",
25290             aliases: ["Burma", "BU"],
25291             groups: ["035", "142", "UN"],
25292             callingCodes: ["95"]
25293           },
25294           geometry: {
25295             type: "MultiPolygon",
25296             coordinates: [[[[92.62187, 21.87037], [92.59775, 21.6092], [92.68152, 21.28454], [92.60187, 21.24615], [92.55105, 21.3856], [92.43158, 21.37025], [92.37939, 21.47764], [92.20087, 21.337], [92.17752, 21.17445], [92.26071, 21.05697], [92.47409, 20.38654], [92.61042, 13.76986], [94.6371, 13.81803], [97.63455, 9.60854], [98.12555, 9.44056], [98.33094, 9.91973], [98.47298, 9.95782], [98.52291, 9.92389], [98.55174, 9.92804], [98.7391, 10.31488], [98.81944, 10.52761], [98.77275, 10.62548], [98.78511, 10.68351], [98.86819, 10.78336], [99.0069, 10.85485], [98.99701, 10.92962], [99.02337, 10.97217], [99.06938, 10.94857], [99.32756, 11.28545], [99.31573, 11.32081], [99.39485, 11.3925], [99.47598, 11.62434], [99.5672, 11.62732], [99.64108, 11.78948], [99.64891, 11.82699], [99.53424, 12.02317], [99.56445, 12.14805], [99.47519, 12.1353], [99.409, 12.60603], [99.29254, 12.68921], [99.18905, 12.84799], [99.18748, 12.9898], [99.10646, 13.05804], [99.12225, 13.19847], [99.20617, 13.20575], [99.16695, 13.72621], [98.97356, 14.04868], [98.56762, 14.37701], [98.24874, 14.83013], [98.18821, 15.13125], [98.22, 15.21327], [98.30446, 15.30667], [98.40522, 15.25268], [98.41906, 15.27103], [98.39351, 15.34177], [98.4866, 15.39154], [98.56027, 15.33471], [98.58598, 15.46821], [98.541, 15.65406], [98.59853, 15.87197], [98.57019, 16.04578], [98.69585, 16.13353], [98.8376, 16.11706], [98.92656, 16.36425], [98.84485, 16.42354], [98.68074, 16.27068], [98.63817, 16.47424], [98.57912, 16.55983], [98.5695, 16.62826], [98.51113, 16.64503], [98.51833, 16.676], [98.51472, 16.68521], [98.51579, 16.69433], [98.51043, 16.70107], [98.49713, 16.69022], [98.50253, 16.7139], [98.46994, 16.73613], [98.53833, 16.81934], [98.49603, 16.8446], [98.52624, 16.89979], [98.39441, 17.06266], [98.34566, 17.04822], [98.10439, 17.33847], [98.11185, 17.36829], [97.91829, 17.54504], [97.76407, 17.71595], [97.66794, 17.88005], [97.73723, 17.97912], [97.60841, 18.23846], [97.64116, 18.29778], [97.56219, 18.33885], [97.50383, 18.26844], [97.34522, 18.54596], [97.36444, 18.57138], [97.5258, 18.4939], [97.76752, 18.58097], [97.73836, 18.88478], [97.66487, 18.9371], [97.73654, 18.9812], [97.73797, 19.04261], [97.83479, 19.09972], [97.84024, 19.22217], [97.78606, 19.26769], [97.84186, 19.29526], [97.78769, 19.39429], [97.88423, 19.5041], [97.84715, 19.55782], [98.04364, 19.65755], [98.03314, 19.80941], [98.13829, 19.78541], [98.24884, 19.67876], [98.51182, 19.71303], [98.56065, 19.67807], [98.83661, 19.80931], [98.98679, 19.7419], [99.0735, 20.10298], [99.20328, 20.12877], [99.416, 20.08614], [99.52943, 20.14811], [99.5569, 20.20676], [99.46077, 20.36198], [99.46008, 20.39673], [99.68255, 20.32077], [99.81096, 20.33687], [99.86383, 20.44371], [99.88211, 20.44488], [99.88451, 20.44596], [99.89168, 20.44548], [99.89301, 20.44311], [99.89692, 20.44789], [99.90499, 20.4487], [99.91616, 20.44986], [99.95721, 20.46301], [100.08404, 20.36626], [100.1957, 20.68247], [100.36375, 20.82783], [100.51079, 20.82194], [100.60112, 20.8347], [100.64628, 20.88279], [100.50974, 20.88574], [100.55281, 21.02796], [100.63578, 21.05639], [100.72716, 21.31786], [100.80173, 21.2934], [101.00234, 21.39612], [101.16198, 21.52808], [101.15156, 21.56129], [101.11744, 21.77659], [100.87265, 21.67396], [100.72143, 21.51898], [100.57861, 21.45637], [100.4811, 21.46148], [100.42892, 21.54325], [100.35201, 21.53176], [100.25863, 21.47043], [100.18447, 21.51898], [100.1625, 21.48704], [100.12542, 21.50365], [100.10757, 21.59945], [100.17486, 21.65306], [100.12679, 21.70539], [100.04956, 21.66843], [99.98654, 21.71064], [99.94003, 21.82782], [99.99084, 21.97053], [99.96612, 22.05965], [99.85351, 22.04183], [99.47585, 22.13345], [99.33166, 22.09656], [99.1552, 22.15874], [99.19176, 22.16983], [99.17318, 22.18025], [99.28771, 22.4105], [99.37972, 22.50188], [99.38247, 22.57544], [99.31243, 22.73893], [99.45654, 22.85726], [99.43537, 22.94086], [99.54218, 22.90014], [99.52214, 23.08218], [99.34127, 23.13099], [99.25741, 23.09025], [99.04601, 23.12215], [99.05975, 23.16382], [98.88597, 23.18656], [98.92515, 23.29535], [98.93958, 23.31414], [98.87573, 23.33038], [98.92104, 23.36946], [98.87683, 23.48995], [98.82877, 23.47908], [98.80294, 23.5345], [98.88396, 23.59555], [98.81775, 23.694], [98.82933, 23.72921], [98.79607, 23.77947], [98.68209, 23.80492], [98.67797, 23.9644], [98.89632, 24.10612], [98.87998, 24.15624], [98.85319, 24.13042], [98.59256, 24.08371], [98.54476, 24.13119], [98.20666, 24.11406], [98.07806, 24.07988], [98.06703, 24.08028], [98.0607, 24.07812], [98.05671, 24.07961], [98.05302, 24.07408], [98.04709, 24.07616], [97.99583, 24.04932], [97.98691, 24.03897], [97.93951, 24.01953], [97.90998, 24.02094], [97.88616, 24.00463], [97.88414, 23.99405], [97.88814, 23.98605], [97.89683, 23.98389], [97.89676, 23.97931], [97.8955, 23.97758], [97.88811, 23.97446], [97.86545, 23.97723], [97.84328, 23.97603], [97.79416, 23.95663], [97.79456, 23.94836], [97.72302, 23.89288], [97.64667, 23.84574], [97.5247, 23.94032], [97.62363, 24.00506], [97.72903, 24.12606], [97.75305, 24.16902], [97.72799, 24.18883], [97.72998, 24.2302], [97.76799, 24.26365], [97.71941, 24.29652], [97.66723, 24.30027], [97.65624, 24.33781], [97.7098, 24.35658], [97.66998, 24.45288], [97.60029, 24.4401], [97.52757, 24.43748], [97.56286, 24.54535], [97.56525, 24.72838], [97.54675, 24.74202], [97.5542, 24.74943], [97.56383, 24.75535], [97.56648, 24.76475], [97.64354, 24.79171], [97.70181, 24.84557], [97.73127, 24.83015], [97.76481, 24.8289], [97.79949, 24.85655], [97.72903, 24.91332], [97.72216, 25.08508], [97.77023, 25.11492], [97.83614, 25.2715], [97.92541, 25.20815], [98.14925, 25.41547], [98.12591, 25.50722], [98.18084, 25.56298], [98.16848, 25.62739], [98.25774, 25.6051], [98.31268, 25.55307], [98.40606, 25.61129], [98.54064, 25.85129], [98.63128, 25.79937], [98.70818, 25.86241], [98.60763, 26.01512], [98.57085, 26.11547], [98.63128, 26.15492], [98.66884, 26.09165], [98.7329, 26.17218], [98.67797, 26.24487], [98.72741, 26.36183], [98.77547, 26.61994], [98.7333, 26.85615], [98.69582, 27.56499], [98.43353, 27.67086], [98.42529, 27.55404], [98.32641, 27.51385], [98.13964, 27.9478], [98.15337, 28.12114], [97.90069, 28.3776], [97.79632, 28.33168], [97.70705, 28.5056], [97.56835, 28.55628], [97.50518, 28.49716], [97.47085, 28.2688], [97.41729, 28.29783], [97.34547, 28.21385], [97.31292, 28.06784], [97.35412, 28.06663], [97.38845, 28.01329], [97.35824, 27.87256], [97.29919, 27.92233], [96.90112, 27.62149], [96.91431, 27.45752], [97.17422, 27.14052], [97.14675, 27.09041], [96.89132, 27.17474], [96.85287, 27.2065], [96.88445, 27.25046], [96.73888, 27.36638], [96.55761, 27.29928], [96.40779, 27.29818], [96.15591, 27.24572], [96.04949, 27.19428], [95.93002, 27.04149], [95.81603, 27.01335], [95.437, 26.7083], [95.30339, 26.65372], [95.23513, 26.68499], [95.05798, 26.45408], [95.12801, 26.38397], [95.11428, 26.1019], [95.18556, 26.07338], [94.80117, 25.49359], [94.68032, 25.47003], [94.57458, 25.20318], [94.74212, 25.13606], [94.73937, 25.00545], [94.60204, 24.70889], [94.5526, 24.70764], [94.50729, 24.59281], [94.45279, 24.56656], [94.32362, 24.27692], [94.30215, 24.23752], [94.14081, 23.83333], [93.92089, 23.95812], [93.80279, 23.92549], [93.75952, 24.0003], [93.62871, 24.00922], [93.50616, 23.94432], [93.46633, 23.97067], [93.41415, 24.07854], [93.34735, 24.10151], [93.32351, 24.04468], [93.36059, 23.93176], [93.3908, 23.92925], [93.3908, 23.7622], [93.43475, 23.68299], [93.38805, 23.4728], [93.39981, 23.38828], [93.38781, 23.36139], [93.36862, 23.35426], [93.38478, 23.13698], [93.2878, 23.00464], [93.12988, 23.05772], [93.134, 22.92498], [93.09417, 22.69459], [93.134, 22.59573], [93.11477, 22.54374], [93.13537, 22.45873], [93.18206, 22.43716], [93.19991, 22.25425], [93.14224, 22.24535], [93.15734, 22.18687], [93.04885, 22.20595], [92.99255, 22.05965], [92.99804, 21.98964], [92.93899, 22.02656], [92.89504, 21.95143], [92.86208, 22.05456], [92.70416, 22.16017], [92.67532, 22.03547], [92.60949, 21.97638], [92.62187, 21.87037]]]]
25297           }
25298         }, {
25299           type: "Feature",
25300           properties: {
25301             iso1A2: "MN",
25302             iso1A3: "MNG",
25303             iso1N3: "496",
25304             wikidata: "Q711",
25305             nameEn: "Mongolia",
25306             groups: ["030", "142", "UN"],
25307             callingCodes: ["976"]
25308           },
25309           geometry: {
25310             type: "MultiPolygon",
25311             coordinates: [[[[102.14032, 51.35566], [101.5044, 51.50467], [101.39085, 51.45753], [100.61116, 51.73028], [99.89203, 51.74903], [99.75578, 51.90108], [99.27888, 51.96876], [98.87768, 52.14563], [98.74142, 51.8637], [98.33222, 51.71832], [98.22053, 51.46579], [98.05257, 51.46696], [97.83305, 51.00248], [98.01472, 50.86652], [97.9693, 50.78044], [98.06393, 50.61262], [98.31373, 50.4996], [98.29481, 50.33561], [97.85197, 49.91339], [97.76871, 49.99861], [97.56432, 49.92801], [97.56811, 49.84265], [97.24639, 49.74737], [96.97388, 49.88413], [95.80056, 50.04239], [95.74757, 49.97915], [95.02465, 49.96941], [94.97166, 50.04725], [94.6121, 50.04239], [94.49477, 50.17832], [94.39258, 50.22193], [94.30823, 50.57498], [92.99595, 50.63183], [93.01109, 50.79001], [92.44714, 50.78762], [92.07173, 50.69585], [91.86048, 50.73734], [89.59711, 49.90851], [89.70687, 49.72535], [88.82499, 49.44808], [88.42449, 49.48821], [88.17223, 49.46934], [88.15543, 49.30314], [87.98977, 49.18147], [87.81333, 49.17354], [87.88171, 48.95853], [87.73822, 48.89582], [88.0788, 48.71436], [87.96361, 48.58478], [88.58939, 48.34531], [88.58316, 48.21893], [88.8011, 48.11302], [88.93186, 48.10263], [89.0711, 47.98528], [89.55453, 48.0423], [89.76624, 47.82745], [90.06512, 47.88177], [90.10871, 47.7375], [90.33598, 47.68303], [90.48854, 47.41826], [90.48542, 47.30438], [90.76108, 46.99399], [90.84035, 46.99525], [91.03649, 46.72916], [91.0147, 46.58171], [91.07696, 46.57315], [90.89639, 46.30711], [90.99672, 46.14207], [91.03026, 46.04194], [90.70907, 45.73437], [90.65114, 45.49314], [90.89169, 45.19667], [91.64048, 45.07408], [93.51161, 44.95964], [94.10003, 44.71016], [94.71959, 44.35284], [95.01191, 44.25274], [95.39772, 44.2805], [95.32891, 44.02407], [95.52594, 43.99353], [95.89543, 43.2528], [96.35658, 42.90363], [96.37926, 42.72055], [97.1777, 42.7964], [99.50671, 42.56535], [100.33297, 42.68231], [100.84979, 42.67087], [101.80515, 42.50074], [102.07645, 42.22519], [102.72403, 42.14675], [103.92804, 41.78246], [104.52258, 41.8706], [104.51667, 41.66113], [105.0123, 41.63188], [106.76517, 42.28741], [107.24774, 42.36107], [107.29755, 42.41395], [107.49681, 42.46221], [107.57258, 42.40898], [108.84489, 42.40246], [109.00679, 42.45302], [109.452, 42.44842], [109.89402, 42.63111], [110.08401, 42.6411], [110.4327, 42.78293], [111.0149, 43.3289], [111.59087, 43.51207], [111.79758, 43.6637], [111.93776, 43.68709], [111.96289, 43.81596], [111.40498, 44.3461], [111.76275, 44.98032], [111.98695, 45.09074], [112.4164, 45.06858], [112.74662, 44.86297], [113.70918, 44.72891], [114.5166, 45.27189], [114.54801, 45.38337], [114.74612, 45.43585], [114.94546, 45.37377], [115.60329, 45.44717], [116.16989, 45.68603], [116.27366, 45.78637], [116.24012, 45.8778], [116.26678, 45.96479], [116.58612, 46.30211], [116.75551, 46.33083], [116.83166, 46.38637], [117.36609, 46.36335], [117.41782, 46.57862], [117.60748, 46.59771], [117.69554, 46.50991], [118.30534, 46.73519], [118.78747, 46.68689], [118.8337, 46.77742], [118.89974, 46.77139], [118.92616, 46.72765], [119.00541, 46.74273], [119.10448, 46.65516], [119.24978, 46.64761], [119.32827, 46.61433], [119.42827, 46.63783], [119.65265, 46.62342], [119.68127, 46.59015], [119.77373, 46.62947], [119.80455, 46.67631], [119.89261, 46.66423], [119.91242, 46.90091], [119.85518, 46.92196], [119.71209, 47.19192], [119.62403, 47.24575], [119.56019, 47.24874], [119.54918, 47.29505], [119.31964, 47.42617], [119.35892, 47.48104], [119.13995, 47.53997], [119.12343, 47.66458], [118.7564, 47.76947], [118.55766, 47.99277], [118.29654, 48.00246], [118.22677, 48.03853], [118.11009, 48.04], [118.03676, 48.00982], [117.80196, 48.01661], [117.50181, 47.77216], [117.37875, 47.63627], [116.9723, 47.87285], [116.67405, 47.89039], [116.4465, 47.83662], [116.21879, 47.88505], [115.94296, 47.67741], [115.57128, 47.91988], [115.52082, 48.15367], [115.811, 48.25699], [115.78876, 48.51781], [116.06565, 48.81716], [116.03781, 48.87014], [116.71193, 49.83813], [116.62502, 49.92919], [116.22402, 50.04477], [115.73602, 49.87688], [115.26068, 49.97367], [114.9703, 50.19254], [114.325, 50.28098], [113.20216, 49.83356], [113.02647, 49.60772], [110.64493, 49.1816], [110.39891, 49.25083], [110.24373, 49.16676], [109.51325, 49.22859], [109.18017, 49.34709], [108.53969, 49.32325], [108.27937, 49.53167], [107.95387, 49.66659], [107.96116, 49.93191], [107.36407, 49.97612], [107.1174, 50.04239], [107.00007, 50.1977], [106.80326, 50.30177], [106.58373, 50.34044], [106.51122, 50.34408], [106.49628, 50.32436], [106.47156, 50.31909], [106.07865, 50.33474], [106.05562, 50.40582], [105.32528, 50.4648], [103.70343, 50.13952], [102.71178, 50.38873], [102.32194, 50.67982], [102.14032, 51.35566]]]]
25312           }
25313         }, {
25314           type: "Feature",
25315           properties: {
25316             iso1A2: "MO",
25317             iso1A3: "MAC",
25318             iso1N3: "446",
25319             wikidata: "Q14773",
25320             nameEn: "Macau",
25321             aliases: ["Macao"],
25322             country: "CN",
25323             groups: ["030", "142", "UN"],
25324             driveSide: "left",
25325             callingCodes: ["853"]
25326           },
25327           geometry: {
25328             type: "MultiPolygon",
25329             coordinates: [[[[113.54942, 22.14519], [113.54839, 22.10909], [113.57191, 22.07696], [113.63011, 22.10782], [113.60504, 22.20464], [113.57123, 22.20416], [113.56865, 22.20973], [113.5508, 22.21672], [113.54333, 22.21688], [113.54093, 22.21314], [113.53593, 22.2137], [113.53301, 22.21235], [113.53552, 22.20607], [113.52659, 22.18271], [113.54093, 22.15497], [113.54942, 22.14519]]]]
25330           }
25331         }, {
25332           type: "Feature",
25333           properties: {
25334             iso1A2: "MP",
25335             iso1A3: "MNP",
25336             iso1N3: "580",
25337             wikidata: "Q16644",
25338             nameEn: "Northern Mariana Islands",
25339             aliases: ["US-MP"],
25340             country: "US",
25341             groups: ["Q1352230", "Q153732", "057", "009", "UN"],
25342             roadSpeedUnit: "mph",
25343             callingCodes: ["1 670"]
25344           },
25345           geometry: {
25346             type: "MultiPolygon",
25347             coordinates: [[[[135.52896, 14.32623], [152.19114, 13.63487], [145.05972, 21.28731], [135.52896, 14.32623]]]]
25348           }
25349         }, {
25350           type: "Feature",
25351           properties: {
25352             iso1A2: "MQ",
25353             iso1A3: "MTQ",
25354             iso1N3: "474",
25355             wikidata: "Q17054",
25356             nameEn: "Martinique",
25357             country: "FR",
25358             groups: ["Q3320166", "EU", "029", "003", "419", "019", "UN"],
25359             callingCodes: ["596"]
25360           },
25361           geometry: {
25362             type: "MultiPolygon",
25363             coordinates: [[[[-59.95997, 14.20285], [-61.07821, 15.25109], [-61.69315, 14.26451], [-59.95997, 14.20285]]]]
25364           }
25365         }, {
25366           type: "Feature",
25367           properties: {
25368             iso1A2: "MR",
25369             iso1A3: "MRT",
25370             iso1N3: "478",
25371             wikidata: "Q1025",
25372             nameEn: "Mauritania",
25373             groups: ["011", "202", "002", "UN"],
25374             callingCodes: ["222"]
25375           },
25376           geometry: {
25377             type: "MultiPolygon",
25378             coordinates: [[[[-5.60725, 16.49919], [-6.57191, 25.0002], [-4.83423, 24.99935], [-8.66674, 27.31569], [-8.66721, 25.99918], [-12.0002, 25.9986], [-12.00251, 23.4538], [-12.14969, 23.41935], [-12.36213, 23.3187], [-12.5741, 23.28975], [-13.00412, 23.02297], [-13.10753, 22.89493], [-13.15313, 22.75649], [-13.08438, 22.53866], [-13.01525, 21.33343], [-16.95474, 21.33997], [-16.99806, 21.12142], [-17.0357, 21.05368], [-17.0396, 20.9961], [-17.06781, 20.92697], [-17.0695, 20.85742], [-17.0471, 20.76408], [-17.15288, 16.07139], [-16.50854, 16.09032], [-16.48967, 16.0496], [-16.44814, 16.09753], [-16.4429, 16.20605], [-16.27016, 16.51565], [-15.6509, 16.50315], [-15.00557, 16.64997], [-14.32144, 16.61495], [-13.80075, 16.13961], [-13.43135, 16.09022], [-13.11029, 15.52116], [-12.23936, 14.76324], [-11.94903, 14.76143], [-11.70705, 15.51558], [-11.43483, 15.62339], [-10.90932, 15.11001], [-10.71721, 15.4223], [-9.40447, 15.4396], [-9.44673, 15.60553], [-9.33314, 15.7044], [-9.31106, 15.69412], [-9.32979, 15.50032], [-5.50165, 15.50061], [-5.33435, 16.33354], [-5.60725, 16.49919]]]]
25379           }
25380         }, {
25381           type: "Feature",
25382           properties: {
25383             iso1A2: "MS",
25384             iso1A3: "MSR",
25385             iso1N3: "500",
25386             wikidata: "Q13353",
25387             nameEn: "Montserrat",
25388             country: "GB",
25389             groups: ["BOTS", "029", "003", "419", "019", "UN"],
25390             driveSide: "left",
25391             roadSpeedUnit: "mph",
25392             roadHeightUnit: "ft",
25393             callingCodes: ["1 664"]
25394           },
25395           geometry: {
25396             type: "MultiPolygon",
25397             coordinates: [[[[-61.91508, 16.51165], [-62.1023, 16.97277], [-62.58307, 16.68909], [-61.91508, 16.51165]]]]
25398           }
25399         }, {
25400           type: "Feature",
25401           properties: {
25402             iso1A2: "MT",
25403             iso1A3: "MLT",
25404             iso1N3: "470",
25405             wikidata: "Q233",
25406             nameEn: "Malta",
25407             groups: ["EU", "039", "150", "UN"],
25408             driveSide: "left",
25409             callingCodes: ["356"]
25410           },
25411           geometry: {
25412             type: "MultiPolygon",
25413             coordinates: [[[[15.70991, 35.79901], [14.07544, 36.41525], [13.27636, 35.20764], [15.70991, 35.79901]]]]
25414           }
25415         }, {
25416           type: "Feature",
25417           properties: {
25418             iso1A2: "MU",
25419             iso1A3: "MUS",
25420             iso1N3: "480",
25421             wikidata: "Q1027",
25422             nameEn: "Mauritius",
25423             groups: ["014", "202", "002", "UN"],
25424             driveSide: "left",
25425             callingCodes: ["230"]
25426           },
25427           geometry: {
25428             type: "MultiPolygon",
25429             coordinates: [[[[56.09755, -9.55401], [57.50644, -31.92637], [68.4673, -19.15185], [56.09755, -9.55401]]]]
25430           }
25431         }, {
25432           type: "Feature",
25433           properties: {
25434             iso1A2: "MV",
25435             iso1A3: "MDV",
25436             iso1N3: "462",
25437             wikidata: "Q826",
25438             nameEn: "Maldives",
25439             groups: ["034", "142", "UN"],
25440             driveSide: "left",
25441             callingCodes: ["960"]
25442           },
25443           geometry: {
25444             type: "MultiPolygon",
25445             coordinates: [[[[71.9161, 8.55531], [72.57428, -3.7623], [76.59015, 5.591], [71.9161, 8.55531]]]]
25446           }
25447         }, {
25448           type: "Feature",
25449           properties: {
25450             iso1A2: "MW",
25451             iso1A3: "MWI",
25452             iso1N3: "454",
25453             wikidata: "Q1020",
25454             nameEn: "Malawi",
25455             groups: ["014", "202", "002", "UN"],
25456             driveSide: "left",
25457             callingCodes: ["265"]
25458           },
25459           geometry: {
25460             type: "MultiPolygon",
25461             coordinates: [[[[33.48052, -9.62442], [33.31581, -9.48554], [33.14925, -9.49322], [32.99397, -9.36712], [32.95389, -9.40138], [33.00476, -9.5133], [33.00256, -9.63053], [33.05485, -9.61316], [33.10163, -9.66525], [33.12144, -9.58929], [33.2095, -9.61099], [33.31517, -9.82364], [33.36581, -9.81063], [33.37902, -9.9104], [33.31297, -10.05133], [33.53863, -10.20148], [33.54797, -10.36077], [33.70675, -10.56896], [33.47636, -10.78465], [33.28022, -10.84428], [33.25998, -10.88862], [33.39697, -11.15296], [33.29267, -11.3789], [33.29267, -11.43536], [33.23663, -11.40637], [33.24252, -11.59302], [33.32692, -11.59248], [33.33937, -11.91252], [33.25998, -12.14242], [33.3705, -12.34931], [33.47636, -12.32498], [33.54485, -12.35996], [33.37517, -12.54085], [33.28177, -12.54692], [33.18837, -12.61377], [33.05917, -12.59554], [32.94397, -12.76868], [32.96733, -12.88251], [33.02181, -12.88707], [32.98289, -13.12671], [33.0078, -13.19492], [32.86113, -13.47292], [32.84176, -13.52794], [32.73683, -13.57682], [32.68436, -13.55769], [32.66468, -13.60019], [32.68654, -13.64268], [32.7828, -13.64805], [32.84528, -13.71576], [32.76962, -13.77224], [32.79015, -13.80755], [32.88985, -13.82956], [32.99042, -13.95689], [33.02977, -14.05022], [33.07568, -13.98447], [33.16749, -13.93992], [33.24249, -14.00019], [33.66677, -14.61306], [33.7247, -14.4989], [33.88503, -14.51652], [33.92898, -14.47929], [34.08588, -14.48893], [34.18733, -14.43823], [34.22355, -14.43607], [34.34453, -14.3985], [34.35843, -14.38652], [34.39277, -14.39467], [34.4192, -14.43191], [34.44641, -14.47746], [34.45053, -14.49873], [34.47628, -14.53363], [34.48932, -14.53646], [34.49636, -14.55091], [34.52366, -14.5667], [34.53962, -14.59776], [34.55112, -14.64494], [34.53516, -14.67782], [34.52057, -14.68263], [34.54503, -14.74672], [34.567, -14.77345], [34.61522, -14.99583], [34.57503, -15.30619], [34.43126, -15.44778], [34.44981, -15.60864], [34.25195, -15.90321], [34.43126, -16.04737], [34.40344, -16.20923], [35.04805, -16.83167], [35.13771, -16.81687], [35.17017, -16.93521], [35.04805, -17.00027], [35.0923, -17.13235], [35.3062, -17.1244], [35.27065, -16.93817], [35.30929, -16.82871], [35.27219, -16.69402], [35.14235, -16.56812], [35.25828, -16.4792], [35.30157, -16.2211], [35.43355, -16.11371], [35.52365, -16.15414], [35.70107, -16.10147], [35.80487, -16.03907], [35.85303, -15.41913], [35.78799, -15.17428], [35.91812, -14.89514], [35.87212, -14.89478], [35.86945, -14.67481], [35.5299, -14.27714], [35.47989, -14.15594], [34.86229, -13.48958], [34.60253, -13.48487], [34.37831, -12.17408], [34.46088, -12.0174], [34.70739, -12.15652], [34.82903, -12.04837], [34.57917, -11.87849], [34.64241, -11.57499], [34.96296, -11.57354], [34.91153, -11.39799], [34.79375, -11.32245], [34.63305, -11.11731], [34.61161, -11.01611], [34.67047, -10.93796], [34.65946, -10.6828], [34.57581, -10.56271], [34.51911, -10.12279], [34.54499, -10.0678], [34.03865, -9.49398], [33.95829, -9.54066], [33.9638, -9.62206], [33.93298, -9.71647], [33.76677, -9.58516], [33.48052, -9.62442]]]]
25462           }
25463         }, {
25464           type: "Feature",
25465           properties: {
25466             iso1A2: "MX",
25467             iso1A3: "MEX",
25468             iso1N3: "484",
25469             wikidata: "Q96",
25470             nameEn: "Mexico",
25471             groups: ["013", "003", "419", "019", "UN"],
25472             callingCodes: ["52"]
25473           },
25474           geometry: {
25475             type: "MultiPolygon",
25476             coordinates: [[[[-117.1243, 32.53427], [-118.48109, 32.5991], [-120.12904, 18.41089], [-92.37213, 14.39277], [-92.2261, 14.53423], [-92.1454, 14.6804], [-92.18161, 14.84147], [-92.1423, 14.88647], [-92.1454, 14.98143], [-92.0621, 15.07406], [-92.20983, 15.26077], [-91.73182, 16.07371], [-90.44567, 16.07573], [-90.40499, 16.40524], [-90.61212, 16.49832], [-90.69064, 16.70697], [-91.04436, 16.92175], [-91.43809, 17.25373], [-90.99199, 17.25192], [-90.98678, 17.81655], [-89.14985, 17.81563], [-89.15105, 17.95104], [-89.03839, 18.0067], [-88.8716, 17.89535], [-88.71505, 18.0707], [-88.48242, 18.49164], [-88.3268, 18.49048], [-88.29909, 18.47591], [-88.26593, 18.47617], [-88.03238, 18.41778], [-88.03165, 18.16657], [-87.90671, 18.15213], [-87.87604, 18.18313], [-87.86657, 18.19971], [-87.85693, 18.18266], [-87.84815, 18.18511], [-86.92368, 17.61462], [-85.9092, 21.8218], [-96.92418, 25.97377], [-97.13927, 25.96583], [-97.35946, 25.92189], [-97.37332, 25.83854], [-97.42511, 25.83969], [-97.45669, 25.86874], [-97.49828, 25.89877], [-97.52025, 25.88518], [-97.66511, 26.01708], [-97.95155, 26.0625], [-97.97017, 26.05232], [-98.24603, 26.07191], [-98.27075, 26.09457], [-98.30491, 26.10475], [-98.35126, 26.15129], [-99.00546, 26.3925], [-99.03053, 26.41249], [-99.08477, 26.39849], [-99.53573, 27.30926], [-99.49744, 27.43746], [-99.482, 27.47128], [-99.48045, 27.49016], [-99.50208, 27.50021], [-99.52955, 27.49747], [-99.51478, 27.55836], [-99.55409, 27.61314], [-100.50029, 28.66117], [-100.51222, 28.70679], [-100.5075, 28.74066], [-100.52313, 28.75598], [-100.59809, 28.88197], [-100.63689, 28.90812], [-100.67294, 29.09744], [-100.79696, 29.24688], [-100.87982, 29.296], [-100.94056, 29.33371], [-100.94579, 29.34523], [-100.96725, 29.3477], [-101.01128, 29.36947], [-101.05686, 29.44738], [-101.47277, 29.7744], [-102.60596, 29.8192], [-103.15787, 28.93865], [-104.37752, 29.54255], [-104.39363, 29.55396], [-104.3969, 29.57105], [-104.5171, 29.64671], [-104.77674, 30.4236], [-106.00363, 31.39181], [-106.09025, 31.40569], [-106.20346, 31.46305], [-106.23711, 31.51262], [-106.24612, 31.54193], [-106.28084, 31.56173], [-106.30305, 31.62154], [-106.33419, 31.66303], [-106.34864, 31.69663], [-106.3718, 31.71165], [-106.38003, 31.73151], [-106.41773, 31.75196], [-106.43419, 31.75478], [-106.45244, 31.76523], [-106.46726, 31.75998], [-106.47298, 31.75054], [-106.48815, 31.74769], [-106.50111, 31.75714], [-106.50962, 31.76155], [-106.51251, 31.76922], [-106.52266, 31.77509], [-106.529, 31.784], [-108.20899, 31.78534], [-108.20979, 31.33316], [-111.07523, 31.33232], [-114.82011, 32.49609], [-114.79524, 32.55731], [-114.81141, 32.55543], [-114.80584, 32.62028], [-114.76736, 32.64094], [-114.71871, 32.71894], [-115.88053, 32.63624], [-117.1243, 32.53427]]]]
25477           }
25478         }, {
25479           type: "Feature",
25480           properties: {
25481             iso1A2: "MY",
25482             iso1A3: "MYS",
25483             iso1N3: "458",
25484             wikidata: "Q833",
25485             nameEn: "Malaysia"
25486           },
25487           geometry: null
25488         }, {
25489           type: "Feature",
25490           properties: {
25491             iso1A2: "MZ",
25492             iso1A3: "MOZ",
25493             iso1N3: "508",
25494             wikidata: "Q1029",
25495             nameEn: "Mozambique",
25496             groups: ["014", "202", "002", "UN"],
25497             driveSide: "left",
25498             callingCodes: ["258"]
25499           },
25500           geometry: {
25501             type: "MultiPolygon",
25502             coordinates: [[[[40.74206, -10.25691], [40.44265, -10.4618], [40.00295, -10.80255], [39.58249, -10.96043], [39.24395, -11.17433], [38.88996, -11.16978], [38.47258, -11.4199], [38.21598, -11.27289], [37.93618, -11.26228], [37.8388, -11.3123], [37.76614, -11.53352], [37.3936, -11.68949], [36.80309, -11.56836], [36.62068, -11.72884], [36.19094, -11.70008], [36.19094, -11.57593], [35.82767, -11.41081], [35.63599, -11.55927], [34.96296, -11.57354], [34.64241, -11.57499], [34.57917, -11.87849], [34.82903, -12.04837], [34.70739, -12.15652], [34.46088, -12.0174], [34.37831, -12.17408], [34.60253, -13.48487], [34.86229, -13.48958], [35.47989, -14.15594], [35.5299, -14.27714], [35.86945, -14.67481], [35.87212, -14.89478], [35.91812, -14.89514], [35.78799, -15.17428], [35.85303, -15.41913], [35.80487, -16.03907], [35.70107, -16.10147], [35.52365, -16.15414], [35.43355, -16.11371], [35.30157, -16.2211], [35.25828, -16.4792], [35.14235, -16.56812], [35.27219, -16.69402], [35.30929, -16.82871], [35.27065, -16.93817], [35.3062, -17.1244], [35.0923, -17.13235], [35.04805, -17.00027], [35.17017, -16.93521], [35.13771, -16.81687], [35.04805, -16.83167], [34.40344, -16.20923], [34.43126, -16.04737], [34.25195, -15.90321], [34.44981, -15.60864], [34.43126, -15.44778], [34.57503, -15.30619], [34.61522, -14.99583], [34.567, -14.77345], [34.54503, -14.74672], [34.52057, -14.68263], [34.53516, -14.67782], [34.55112, -14.64494], [34.53962, -14.59776], [34.52366, -14.5667], [34.49636, -14.55091], [34.48932, -14.53646], [34.47628, -14.53363], [34.45053, -14.49873], [34.44641, -14.47746], [34.4192, -14.43191], [34.39277, -14.39467], [34.35843, -14.38652], [34.34453, -14.3985], [34.22355, -14.43607], [34.18733, -14.43823], [34.08588, -14.48893], [33.92898, -14.47929], [33.88503, -14.51652], [33.7247, -14.4989], [33.66677, -14.61306], [33.24249, -14.00019], [30.22098, -14.99447], [30.41902, -15.62269], [30.42568, -15.9962], [30.91597, -15.99924], [30.97761, -16.05848], [31.13171, -15.98019], [31.30563, -16.01193], [31.42451, -16.15154], [31.67988, -16.19595], [31.90223, -16.34388], [31.91324, -16.41569], [32.02772, -16.43892], [32.28529, -16.43892], [32.42838, -16.4727], [32.71017, -16.59932], [32.69917, -16.66893], [32.78943, -16.70267], [32.97655, -16.70689], [32.91051, -16.89446], [32.84113, -16.92259], [32.96554, -17.11971], [33.00517, -17.30477], [33.0426, -17.3468], [32.96554, -17.48964], [32.98536, -17.55891], [33.0492, -17.60298], [32.94133, -17.99705], [33.03159, -18.35054], [33.02278, -18.4696], [32.88629, -18.51344], [32.88629, -18.58023], [32.95013, -18.69079], [32.9017, -18.7992], [32.82465, -18.77419], [32.70137, -18.84712], [32.73439, -18.92628], [32.69917, -18.94293], [32.72118, -19.02204], [32.84006, -19.0262], [32.87088, -19.09279], [32.85107, -19.29238], [32.77966, -19.36098], [32.78282, -19.47513], [32.84446, -19.48343], [32.84666, -19.68462], [32.95013, -19.67219], [33.06461, -19.77787], [33.01178, -20.02007], [32.93032, -20.03868], [32.85987, -20.16686], [32.85987, -20.27841], [32.66174, -20.56106], [32.55167, -20.56312], [32.48122, -20.63319], [32.51644, -20.91929], [32.37115, -21.133], [32.48236, -21.32873], [32.41234, -21.31246], [31.38336, -22.36919], [31.30611, -22.422], [31.55779, -23.176], [31.56539, -23.47268], [31.67942, -23.60858], [31.70223, -23.72695], [31.77445, -23.90082], [31.87707, -23.95293], [31.90368, -24.18892], [31.9835, -24.29983], [32.03196, -25.10785], [32.01676, -25.38117], [31.97875, -25.46356], [32.00631, -25.65044], [31.92649, -25.84216], [31.974, -25.95387], [32.00916, -25.999], [32.08599, -26.00978], [32.10435, -26.15656], [32.07352, -26.40185], [32.13409, -26.5317], [32.13315, -26.84345], [32.19409, -26.84032], [32.22302, -26.84136], [32.29584, -26.852], [32.35222, -26.86027], [34.51034, -26.91792], [42.99868, -12.65261], [40.74206, -10.25691]]]]
25503           }
25504         }, {
25505           type: "Feature",
25506           properties: {
25507             iso1A2: "NA",
25508             iso1A3: "NAM",
25509             iso1N3: "516",
25510             wikidata: "Q1030",
25511             nameEn: "Namibia",
25512             groups: ["018", "202", "002", "UN"],
25513             driveSide: "left",
25514             callingCodes: ["264"]
25515           },
25516           geometry: {
25517             type: "MultiPolygon",
25518             coordinates: [[[[14.28743, -17.38814], [13.95896, -17.43141], [13.36212, -16.98048], [12.97145, -16.98567], [12.52111, -17.24495], [12.07076, -17.15165], [11.75063, -17.25013], [10.5065, -17.25284], [12.51595, -32.27486], [16.45332, -28.63117], [16.46592, -28.57126], [16.59922, -28.53246], [16.90446, -28.057], [17.15405, -28.08573], [17.4579, -28.68718], [18.99885, -28.89165], [19.99882, -28.42622], [19.99817, -24.76768], [19.99912, -21.99991], [20.99751, -22.00026], [20.99904, -18.31743], [21.45556, -18.31795], [23.0996, -18.00075], [23.29618, -17.99855], [23.61088, -18.4881], [24.19416, -18.01919], [24.40577, -17.95726], [24.57485, -18.07151], [24.6303, -17.9863], [24.71887, -17.9218], [24.73364, -17.89338], [24.95586, -17.79674], [25.05895, -17.84452], [25.16882, -17.78253], [25.26433, -17.79571], [25.00198, -17.58221], [24.70864, -17.49501], [24.5621, -17.52963], [24.38712, -17.46818], [24.32811, -17.49082], [24.23619, -17.47489], [23.47474, -17.62877], [21.42741, -18.02787], [21.14283, -17.94318], [18.84226, -17.80375], [18.39229, -17.38927], [14.28743, -17.38814]]]]
25519           }
25520         }, {
25521           type: "Feature",
25522           properties: {
25523             iso1A2: "NC",
25524             iso1A3: "NCL",
25525             iso1N3: "540",
25526             wikidata: "Q33788",
25527             nameEn: "New Caledonia",
25528             country: "FR",
25529             groups: ["Q1451600", "054", "009", "UN"],
25530             callingCodes: ["687"]
25531           },
25532           geometry: {
25533             type: "MultiPolygon",
25534             coordinates: [[[[159.77159, -28.41151], [174.245, -23.1974], [156.73836, -14.50464], [159.77159, -28.41151]]]]
25535           }
25536         }, {
25537           type: "Feature",
25538           properties: {
25539             iso1A2: "NE",
25540             iso1A3: "NER",
25541             iso1N3: "562",
25542             wikidata: "Q1032",
25543             nameEn: "Niger",
25544             aliases: ["RN"],
25545             groups: ["011", "202", "002", "UN"],
25546             callingCodes: ["227"]
25547           },
25548           geometry: {
25549             type: "MultiPolygon",
25550             coordinates: [[[[14.22918, 22.61719], [13.5631, 23.16574], [11.96886, 23.51735], [7.48273, 20.87258], [7.38361, 20.79165], [5.8153, 19.45101], [4.26651, 19.14224], [4.26762, 17.00432], [4.21787, 17.00118], [4.19893, 16.39923], [3.50368, 15.35934], [3.03134, 15.42221], [3.01806, 15.34571], [1.31275, 15.27978], [0.96711, 14.98275], [0.72632, 14.95898], [0.23859, 15.00135], [0.16936, 14.51654], [0.38051, 14.05575], [0.61924, 13.68491], [0.77377, 13.6866], [0.77637, 13.64442], [0.99514, 13.5668], [1.02813, 13.46635], [1.20088, 13.38951], [1.24429, 13.39373], [1.28509, 13.35488], [1.24516, 13.33968], [1.21217, 13.37853], [1.18873, 13.31771], [0.99253, 13.37515], [0.99167, 13.10727], [2.26349, 12.41915], [2.05785, 12.35539], [2.39723, 11.89473], [2.45824, 11.98672], [2.39657, 12.10952], [2.37783, 12.24804], [2.6593, 12.30631], [2.83978, 12.40585], [3.25352, 12.01467], [3.31613, 11.88495], [3.48187, 11.86092], [3.59375, 11.70269], [3.61075, 11.69181], [3.67988, 11.75429], [3.67122, 11.80865], [3.63063, 11.83042], [3.61955, 11.91847], [3.67775, 11.97599], [3.63136, 12.11826], [3.66364, 12.25884], [3.65111, 12.52223], [3.94339, 12.74979], [4.10006, 12.98862], [4.14367, 13.17189], [4.14186, 13.47586], [4.23456, 13.47725], [4.4668, 13.68286], [4.87425, 13.78], [4.9368, 13.7345], [5.07396, 13.75052], [5.21026, 13.73627], [5.27797, 13.75474], [5.35437, 13.83567], [5.52957, 13.8845], [6.15771, 13.64564], [6.27411, 13.67835], [6.43053, 13.6006], [6.69617, 13.34057], [6.94445, 12.99825], [7.0521, 13.00076], [7.12676, 13.02445], [7.22399, 13.1293], [7.39241, 13.09717], [7.81085, 13.34902], [8.07997, 13.30847], [8.25185, 13.20369], [8.41853, 13.06166], [8.49493, 13.07519], [8.60431, 13.01768], [8.64251, 12.93985], [8.97413, 12.83661], [9.65995, 12.80614], [10.00373, 13.18171], [10.19993, 13.27129], [10.46731, 13.28819], [10.66004, 13.36422], [11.4535, 13.37773], [11.88236, 13.2527], [12.04209, 13.14452], [12.16189, 13.10056], [12.19315, 13.12423], [12.47095, 13.06673], [12.58033, 13.27805], [12.6793, 13.29157], [12.87376, 13.48919], [13.05085, 13.53984], [13.19844, 13.52802], [13.33213, 13.71195], [13.6302, 13.71094], [13.47559, 14.40881], [13.48259, 14.46704], [13.68573, 14.55276], [13.67878, 14.64013], [13.809, 14.72915], [13.78991, 14.87519], [13.86301, 15.04043], [14.37425, 15.72591], [15.50373, 16.89649], [15.6032, 18.77402], [15.75098, 19.93002], [15.99632, 20.35364], [15.6721, 20.70069], [15.59841, 20.74039], [15.56004, 20.79488], [15.55382, 20.86507], [15.57248, 20.92138], [15.62515, 20.95395], [15.28332, 21.44557], [15.20213, 21.49365], [15.19692, 21.99339], [14.99751, 23.00539], [14.22918, 22.61719]]]]
25551           }
25552         }, {
25553           type: "Feature",
25554           properties: {
25555             iso1A2: "NF",
25556             iso1A3: "NFK",
25557             iso1N3: "574",
25558             wikidata: "Q31057",
25559             nameEn: "Norfolk Island",
25560             country: "AU",
25561             groups: ["053", "009", "UN"],
25562             driveSide: "left",
25563             callingCodes: ["672 3"]
25564           },
25565           geometry: {
25566             type: "MultiPolygon",
25567             coordinates: [[[[169.82316, -28.16667], [166.29505, -28.29175], [167.94076, -30.60745], [169.82316, -28.16667]]]]
25568           }
25569         }, {
25570           type: "Feature",
25571           properties: {
25572             iso1A2: "NG",
25573             iso1A3: "NGA",
25574             iso1N3: "566",
25575             wikidata: "Q1033",
25576             nameEn: "Nigeria",
25577             groups: ["011", "202", "002", "UN"],
25578             callingCodes: ["234"]
25579           },
25580           geometry: {
25581             type: "MultiPolygon",
25582             coordinates: [[[[6.15771, 13.64564], [5.52957, 13.8845], [5.35437, 13.83567], [5.27797, 13.75474], [5.21026, 13.73627], [5.07396, 13.75052], [4.9368, 13.7345], [4.87425, 13.78], [4.4668, 13.68286], [4.23456, 13.47725], [4.14186, 13.47586], [4.14367, 13.17189], [4.10006, 12.98862], [3.94339, 12.74979], [3.65111, 12.52223], [3.66364, 12.25884], [3.63136, 12.11826], [3.67775, 11.97599], [3.61955, 11.91847], [3.63063, 11.83042], [3.67122, 11.80865], [3.67988, 11.75429], [3.61075, 11.69181], [3.59375, 11.70269], [3.49175, 11.29765], [3.71505, 11.13015], [3.84243, 10.59316], [3.78292, 10.40538], [3.6844, 10.46351], [3.57275, 10.27185], [3.66908, 10.18136], [3.54429, 9.87739], [3.35383, 9.83641], [3.32099, 9.78032], [3.34726, 9.70696], [3.25093, 9.61632], [3.13928, 9.47167], [3.14147, 9.28375], [3.08017, 9.10006], [2.77907, 9.06924], [2.67523, 7.87825], [2.73095, 7.7755], [2.73405, 7.5423], [2.78668, 7.5116], [2.79442, 7.43486], [2.74489, 7.42565], [2.76965, 7.13543], [2.71702, 6.95722], [2.74024, 6.92802], [2.73405, 6.78508], [2.78823, 6.76356], [2.78204, 6.70514], [2.7325, 6.64057], [2.74334, 6.57291], [2.70464, 6.50831], [2.70566, 6.38038], [2.74181, 6.13349], [5.87055, 3.78489], [8.34397, 4.30689], [8.60302, 4.87353], [8.78027, 5.1243], [8.92029, 5.58403], [8.83687, 5.68483], [8.88156, 5.78857], [8.84209, 5.82562], [9.51757, 6.43874], [9.70674, 6.51717], [9.77824, 6.79088], [9.86314, 6.77756], [10.15135, 7.03781], [10.21466, 6.88996], [10.53639, 6.93432], [10.57214, 7.16345], [10.59746, 7.14719], [10.60789, 7.06885], [10.83727, 6.9358], [10.8179, 6.83377], [10.94302, 6.69325], [11.09644, 6.68437], [11.09495, 6.51717], [11.42041, 6.53789], [11.42264, 6.5882], [11.51499, 6.60892], [11.57755, 6.74059], [11.55818, 6.86186], [11.63117, 6.9905], [11.87396, 7.09398], [11.84864, 7.26098], [11.93205, 7.47812], [12.01844, 7.52981], [11.99908, 7.67302], [12.20909, 7.97553], [12.19271, 8.10826], [12.24782, 8.17904], [12.26123, 8.43696], [12.4489, 8.52536], [12.44146, 8.6152], [12.68722, 8.65938], [12.71701, 8.7595], [12.79, 8.75361], [12.81085, 8.91992], [12.90022, 9.11411], [12.91958, 9.33905], [12.85628, 9.36698], [13.02385, 9.49334], [13.22642, 9.57266], [13.25472, 9.76795], [13.29941, 9.8296], [13.25025, 9.86042], [13.24132, 9.91031], [13.27409, 9.93232], [13.286, 9.9822], [13.25323, 10.00127], [13.25025, 10.03647], [13.34111, 10.12299], [13.43644, 10.13326], [13.5705, 10.53183], [13.54964, 10.61236], [13.73434, 10.9255], [13.70753, 10.94451], [13.7403, 11.00593], [13.78945, 11.00154], [13.97489, 11.30258], [14.17821, 11.23831], [14.6124, 11.51283], [14.64591, 11.66166], [14.55207, 11.72001], [14.61612, 11.7798], [14.6474, 12.17466], [14.4843, 12.35223], [14.22215, 12.36533], [14.17523, 12.41916], [14.20204, 12.53405], [14.08251, 13.0797], [13.6302, 13.71094], [13.33213, 13.71195], [13.19844, 13.52802], [13.05085, 13.53984], [12.87376, 13.48919], [12.6793, 13.29157], [12.58033, 13.27805], [12.47095, 13.06673], [12.19315, 13.12423], [12.16189, 13.10056], [12.04209, 13.14452], [11.88236, 13.2527], [11.4535, 13.37773], [10.66004, 13.36422], [10.46731, 13.28819], [10.19993, 13.27129], [10.00373, 13.18171], [9.65995, 12.80614], [8.97413, 12.83661], [8.64251, 12.93985], [8.60431, 13.01768], [8.49493, 13.07519], [8.41853, 13.06166], [8.25185, 13.20369], [8.07997, 13.30847], [7.81085, 13.34902], [7.39241, 13.09717], [7.22399, 13.1293], [7.12676, 13.02445], [7.0521, 13.00076], [6.94445, 12.99825], [6.69617, 13.34057], [6.43053, 13.6006], [6.27411, 13.67835], [6.15771, 13.64564]]]]
25583           }
25584         }, {
25585           type: "Feature",
25586           properties: {
25587             iso1A2: "NI",
25588             iso1A3: "NIC",
25589             iso1N3: "558",
25590             wikidata: "Q811",
25591             nameEn: "Nicaragua",
25592             groups: ["013", "003", "419", "019", "UN"],
25593             callingCodes: ["505"]
25594           },
25595           geometry: {
25596             type: "MultiPolygon",
25597             coordinates: [[[[-83.13724, 15.00002], [-83.49268, 15.01158], [-83.62101, 14.89448], [-83.89551, 14.76697], [-84.10584, 14.76353], [-84.48373, 14.63249], [-84.70119, 14.68078], [-84.82596, 14.82212], [-84.90082, 14.80489], [-85.1575, 14.53934], [-85.18602, 14.24929], [-85.32149, 14.2562], [-85.45762, 14.11304], [-85.73964, 13.9698], [-85.75477, 13.8499], [-86.03458, 13.99181], [-86.00685, 14.08474], [-86.14801, 14.04317], [-86.35219, 13.77157], [-86.76812, 13.79605], [-86.71267, 13.30348], [-86.87066, 13.30641], [-86.93383, 13.18677], [-86.93197, 13.05313], [-87.03785, 12.98682], [-87.06306, 13.00892], [-87.37107, 12.98646], [-87.55124, 13.12523], [-87.7346, 13.13228], [-88.11443, 12.63306], [-86.14524, 11.09059], [-85.71223, 11.06868], [-85.60529, 11.22607], [-84.92439, 10.9497], [-84.68197, 11.07568], [-83.90838, 10.71161], [-83.66597, 10.79916], [-83.68276, 11.01562], [-82.56142, 11.91792], [-82.06974, 14.49418], [-83.04763, 15.03256], [-83.13724, 15.00002]]]]
25598           }
25599         }, {
25600           type: "Feature",
25601           properties: {
25602             iso1A2: "NL",
25603             iso1A3: "NLD",
25604             iso1N3: "528",
25605             wikidata: "Q29999",
25606             nameEn: "Kingdom of the Netherlands"
25607           },
25608           geometry: null
25609         }, {
25610           type: "Feature",
25611           properties: {
25612             iso1A2: "NO",
25613             iso1A3: "NOR",
25614             iso1N3: "578",
25615             wikidata: "Q20",
25616             nameEn: "Norway"
25617           },
25618           geometry: null
25619         }, {
25620           type: "Feature",
25621           properties: {
25622             iso1A2: "NP",
25623             iso1A3: "NPL",
25624             iso1N3: "524",
25625             wikidata: "Q837",
25626             nameEn: "Nepal",
25627             groups: ["034", "142", "UN"],
25628             driveSide: "left",
25629             callingCodes: ["977"]
25630           },
25631           geometry: {
25632             type: "MultiPolygon",
25633             coordinates: [[[[88.13378, 27.88015], [87.82681, 27.95248], [87.72718, 27.80938], [87.56996, 27.84517], [87.11696, 27.84104], [87.03757, 27.94835], [86.75582, 28.04182], [86.74181, 28.10638], [86.56265, 28.09569], [86.51609, 27.96623], [86.42736, 27.91122], [86.22966, 27.9786], [86.18607, 28.17364], [86.088, 28.09264], [86.08333, 28.02121], [86.12069, 27.93047], [86.06309, 27.90021], [85.94946, 27.9401], [85.97813, 27.99023], [85.90743, 28.05144], [85.84672, 28.18187], [85.74864, 28.23126], [85.71907, 28.38064], [85.69105, 28.38475], [85.60854, 28.25045], [85.59765, 28.30529], [85.4233, 28.32996], [85.38127, 28.28336], [85.10729, 28.34092], [85.18668, 28.54076], [85.19135, 28.62825], [85.06059, 28.68562], [84.85511, 28.58041], [84.62317, 28.73887], [84.47528, 28.74023], [84.2231, 28.89571], [84.24801, 29.02783], [84.18107, 29.23451], [83.97559, 29.33091], [83.82303, 29.30513], [83.63156, 29.16249], [83.44787, 29.30513], [83.28131, 29.56813], [83.07116, 29.61957], [82.73024, 29.81695], [82.5341, 29.9735], [82.38622, 30.02608], [82.16984, 30.0692], [82.19475, 30.16884], [82.10757, 30.23745], [82.10135, 30.35439], [81.99082, 30.33423], [81.62033, 30.44703], [81.5459, 30.37688], [81.41018, 30.42153], [81.39928, 30.21862], [81.33355, 30.15303], [81.2623, 30.14596], [81.29032, 30.08806], [81.24362, 30.0126], [81.12842, 30.01395], [81.03953, 30.20059], [80.92547, 30.17193], [80.91143, 30.22173], [80.86673, 30.17321], [80.8778, 30.13384], [80.67076, 29.95732], [80.60226, 29.95732], [80.57179, 29.91422], [80.56247, 29.86661], [80.48997, 29.79566], [80.43458, 29.80466], [80.41554, 29.79451], [80.36803, 29.73865], [80.38428, 29.68513], [80.41858, 29.63581], [80.37939, 29.57098], [80.24322, 29.44299], [80.31428, 29.30784], [80.28626, 29.20327], [80.24112, 29.21414], [80.26602, 29.13938], [80.23178, 29.11626], [80.18085, 29.13649], [80.05743, 28.91479], [80.06957, 28.82763], [80.12125, 28.82346], [80.37188, 28.63371], [80.44504, 28.63098], [80.52443, 28.54897], [80.50575, 28.6706], [80.55142, 28.69182], [81.03471, 28.40054], [81.19847, 28.36284], [81.32923, 28.13521], [81.38683, 28.17638], [81.48179, 28.12148], [81.47867, 28.08303], [81.91223, 27.84995], [81.97214, 27.93322], [82.06554, 27.92222], [82.46405, 27.6716], [82.70378, 27.72122], [82.74119, 27.49838], [82.93261, 27.50328], [82.94938, 27.46036], [83.19413, 27.45632], [83.27197, 27.38309], [83.2673, 27.36235], [83.29999, 27.32778], [83.35136, 27.33885], [83.38872, 27.39276], [83.39495, 27.4798], [83.61288, 27.47013], [83.85595, 27.35797], [83.86182, 27.4241], [83.93306, 27.44939], [84.02229, 27.43836], [84.10791, 27.52399], [84.21376, 27.45218], [84.25735, 27.44941], [84.29315, 27.39], [84.62161, 27.33885], [84.69166, 27.21294], [84.64496, 27.04669], [84.793, 26.9968], [84.82913, 27.01989], [84.85754, 26.98984], [84.96687, 26.95599], [84.97186, 26.9149], [85.00536, 26.89523], [85.05592, 26.88991], [85.02635, 26.85381], [85.15883, 26.86966], [85.19291, 26.86909], [85.18046, 26.80519], [85.21159, 26.75933], [85.34302, 26.74954], [85.47752, 26.79292], [85.56471, 26.84133], [85.5757, 26.85955], [85.59461, 26.85161], [85.61621, 26.86721], [85.66239, 26.84822], [85.73483, 26.79613], [85.72315, 26.67471], [85.76907, 26.63076], [85.83126, 26.61134], [85.85126, 26.60866], [85.8492, 26.56667], [86.02729, 26.66756], [86.13596, 26.60651], [86.22513, 26.58863], [86.26235, 26.61886], [86.31564, 26.61925], [86.49726, 26.54218], [86.54258, 26.53819], [86.57073, 26.49825], [86.61313, 26.48658], [86.62686, 26.46891], [86.69124, 26.45169], [86.74025, 26.42386], [86.76797, 26.45892], [86.82898, 26.43919], [86.94543, 26.52076], [86.95912, 26.52076], [87.01559, 26.53228], [87.04691, 26.58685], [87.0707, 26.58571], [87.09147, 26.45039], [87.14751, 26.40542], [87.18863, 26.40558], [87.24682, 26.4143], [87.26587, 26.40592], [87.26568, 26.37294], [87.34568, 26.34787], [87.37314, 26.40815], [87.46566, 26.44058], [87.51571, 26.43106], [87.55274, 26.40596], [87.59175, 26.38342], [87.66803, 26.40294], [87.67893, 26.43501], [87.76004, 26.40711], [87.7918, 26.46737], [87.84193, 26.43663], [87.89085, 26.48565], [87.90115, 26.44923], [88.00895, 26.36029], [88.09414, 26.43732], [88.09963, 26.54195], [88.16452, 26.64111], [88.1659, 26.68177], [88.19107, 26.75516], [88.12302, 26.95324], [88.13422, 26.98705], [88.11719, 26.98758], [87.9887, 27.11045], [88.01587, 27.21388], [88.01646, 27.21612], [88.07277, 27.43007], [88.04008, 27.49223], [88.19107, 27.79285], [88.1973, 27.85067], [88.13378, 27.88015]]]]
25634           }
25635         }, {
25636           type: "Feature",
25637           properties: {
25638             iso1A2: "NR",
25639             iso1A3: "NRU",
25640             iso1N3: "520",
25641             wikidata: "Q697",
25642             nameEn: "Nauru",
25643             groups: ["057", "009", "UN"],
25644             driveSide: "left",
25645             callingCodes: ["674"]
25646           },
25647           geometry: {
25648             type: "MultiPolygon",
25649             coordinates: [[[[166.95155, 0.14829], [166.21778, -0.7977], [167.60042, -0.88259], [166.95155, 0.14829]]]]
25650           }
25651         }, {
25652           type: "Feature",
25653           properties: {
25654             iso1A2: "NU",
25655             iso1A3: "NIU",
25656             iso1N3: "570",
25657             wikidata: "Q34020",
25658             nameEn: "Niue",
25659             country: "NZ",
25660             groups: ["061", "009", "UN"],
25661             driveSide: "left",
25662             callingCodes: ["683"]
25663           },
25664           geometry: {
25665             type: "MultiPolygon",
25666             coordinates: [[[[-170.83899, -18.53439], [-170.82274, -20.44429], [-168.63096, -18.60489], [-170.83899, -18.53439]]]]
25667           }
25668         }, {
25669           type: "Feature",
25670           properties: {
25671             iso1A2: "NZ",
25672             iso1A3: "NZL",
25673             iso1N3: "554",
25674             wikidata: "Q664",
25675             nameEn: "New Zealand"
25676           },
25677           geometry: null
25678         }, {
25679           type: "Feature",
25680           properties: {
25681             iso1A2: "OM",
25682             iso1A3: "OMN",
25683             iso1N3: "512",
25684             wikidata: "Q842",
25685             nameEn: "Oman",
25686             groups: ["145", "142", "UN"],
25687             callingCodes: ["968"]
25688           },
25689           geometry: {
25690             type: "MultiPolygon",
25691             coordinates: [[[[56.82555, 25.7713], [56.79239, 26.41236], [56.68954, 26.76645], [56.2644, 26.58649], [55.81777, 26.18798], [56.08666, 26.05038], [56.15498, 26.06828], [56.19334, 25.9795], [56.13963, 25.82765], [56.17416, 25.77239], [56.13579, 25.73524], [56.14826, 25.66351], [56.18363, 25.65508], [56.20473, 25.61119], [56.25365, 25.60211], [56.26636, 25.60643], [56.25341, 25.61443], [56.26534, 25.62825], [56.82555, 25.7713]]], [[[56.26062, 25.33108], [56.23362, 25.31253], [56.25008, 25.28843], [56.24465, 25.27505], [56.20838, 25.25668], [56.20872, 25.24104], [56.24341, 25.22867], [56.27628, 25.23404], [56.34438, 25.26653], [56.35172, 25.30681], [56.3111, 25.30107], [56.3005, 25.31815], [56.26062, 25.33108]], [[56.28423, 25.26344], [56.27086, 25.26128], [56.2716, 25.27916], [56.28102, 25.28486], [56.29379, 25.2754], [56.28423, 25.26344]]], [[[61.45114, 22.55394], [56.86325, 25.03856], [56.3227, 24.97284], [56.34873, 24.93205], [56.30269, 24.88334], [56.20568, 24.85063], [56.20062, 24.78565], [56.13684, 24.73699], [56.06128, 24.74457], [56.03535, 24.81161], [55.97836, 24.87673], [55.97467, 24.89639], [56.05106, 24.87461], [56.05715, 24.95727], [55.96316, 25.00857], [55.90849, 24.96771], [55.85094, 24.96858], [55.81116, 24.9116], [55.81348, 24.80102], [55.83408, 24.77858], [55.83271, 24.68567], [55.76461, 24.5287], [55.83271, 24.41521], [55.83395, 24.32776], [55.80747, 24.31069], [55.79145, 24.27914], [55.76781, 24.26209], [55.75939, 24.26114], [55.75382, 24.2466], [55.75257, 24.23466], [55.76558, 24.23227], [55.77658, 24.23476], [55.83367, 24.20193], [55.95472, 24.2172], [56.01799, 24.07426], [55.8308, 24.01633], [55.73301, 24.05994], [55.48677, 23.94946], [55.57358, 23.669], [55.22634, 23.10378], [55.2137, 22.71065], [55.66469, 21.99658], [54.99756, 20.00083], [52.00311, 19.00083], [52.78009, 17.35124], [52.74267, 17.29519], [52.81185, 17.28568], [57.49095, 8.14549], [61.45114, 22.55394]]]]
25692           }
25693         }, {
25694           type: "Feature",
25695           properties: {
25696             iso1A2: "PA",
25697             iso1A3: "PAN",
25698             iso1N3: "591",
25699             wikidata: "Q804",
25700             nameEn: "Panama",
25701             groups: ["013", "003", "419", "019", "UN"],
25702             callingCodes: ["507"]
25703           },
25704           geometry: {
25705             type: "MultiPolygon",
25706             coordinates: [[[[-77.32389, 8.81247], [-77.58292, 9.22278], [-78.79327, 9.93766], [-82.51044, 9.65379], [-82.56507, 9.57279], [-82.61345, 9.49881], [-82.66667, 9.49746], [-82.77206, 9.59573], [-82.87919, 9.62645], [-82.84871, 9.4973], [-82.93516, 9.46741], [-82.93516, 9.07687], [-82.72126, 8.97125], [-82.88253, 8.83331], [-82.91377, 8.774], [-82.92068, 8.74832], [-82.8794, 8.6981], [-82.82739, 8.60153], [-82.83975, 8.54755], [-82.83322, 8.52464], [-82.8382, 8.48117], [-82.8679, 8.44042], [-82.93056, 8.43465], [-83.05209, 8.33394], [-82.9388, 8.26634], [-82.88641, 8.10219], [-82.89137, 8.05755], [-82.89978, 8.04083], [-82.94503, 7.93865], [-82.13751, 6.97312], [-78.06168, 7.07793], [-77.89178, 7.22681], [-77.81426, 7.48319], [-77.72157, 7.47612], [-77.72514, 7.72348], [-77.57185, 7.51147], [-77.17257, 7.97422], [-77.45064, 8.49991], [-77.32389, 8.81247]]]]
25707           }
25708         }, {
25709           type: "Feature",
25710           properties: {
25711             iso1A2: "PE",
25712             iso1A3: "PER",
25713             iso1N3: "604",
25714             wikidata: "Q419",
25715             nameEn: "Peru",
25716             groups: ["005", "419", "019", "UN"],
25717             callingCodes: ["51"]
25718           },
25719           geometry: {
25720             type: "MultiPolygon",
25721             coordinates: [[[[-74.26675, -0.97229], [-74.42701, -0.50218], [-75.18513, -0.0308], [-75.25764, -0.11943], [-75.40192, -0.17196], [-75.61997, -0.10012], [-75.60169, -0.18708], [-75.53615, -0.19213], [-75.22862, -0.60048], [-75.22862, -0.95588], [-75.3872, -0.9374], [-75.57429, -1.55961], [-76.05203, -2.12179], [-76.6324, -2.58397], [-77.94147, -3.05454], [-78.19369, -3.36431], [-78.14324, -3.47653], [-78.22642, -3.51113], [-78.24589, -3.39907], [-78.34362, -3.38633], [-78.68394, -4.60754], [-78.85149, -4.66795], [-79.01659, -5.01481], [-79.1162, -4.97774], [-79.26248, -4.95167], [-79.59402, -4.46848], [-79.79722, -4.47558], [-80.13945, -4.29786], [-80.39256, -4.48269], [-80.46386, -4.41516], [-80.32114, -4.21323], [-80.45023, -4.20938], [-80.4822, -4.05477], [-80.46386, -4.01342], [-80.13232, -3.90317], [-80.19926, -3.68894], [-80.18741, -3.63994], [-80.19848, -3.59249], [-80.21642, -3.5888], [-80.20535, -3.51667], [-80.22629, -3.501], [-80.23651, -3.48652], [-80.24586, -3.48677], [-80.24123, -3.46124], [-80.20647, -3.431], [-80.30602, -3.39149], [-84.52388, -3.36941], [-85.71054, -21.15413], [-70.59118, -18.35072], [-70.378, -18.3495], [-70.31267, -18.31258], [-70.16394, -18.31737], [-69.96732, -18.25992], [-69.81607, -18.12582], [-69.75305, -17.94605], [-69.82868, -17.72048], [-69.79087, -17.65563], [-69.66483, -17.65083], [-69.46897, -17.4988], [-69.46863, -17.37466], [-69.62883, -17.28142], [-69.16896, -16.72233], [-69.00853, -16.66769], [-69.04027, -16.57214], [-68.98358, -16.42165], [-68.79464, -16.33272], [-68.96238, -16.194], [-69.09986, -16.22693], [-69.20291, -16.16668], [-69.40336, -15.61358], [-69.14856, -15.23478], [-69.36254, -14.94634], [-68.88135, -14.18639], [-69.05265, -13.68546], [-68.8864, -13.40792], [-68.85615, -12.87769], [-68.65044, -12.50689], [-68.98115, -11.8979], [-69.57156, -10.94555], [-69.57835, -10.94051], [-69.90896, -10.92744], [-70.38791, -11.07096], [-70.51395, -10.92249], [-70.64134, -11.0108], [-70.62487, -9.80666], [-70.55429, -9.76692], [-70.58453, -9.58303], [-70.53373, -9.42628], [-71.23394, -9.9668], [-72.14742, -9.98049], [-72.31883, -9.5184], [-72.72216, -9.41397], [-73.21498, -9.40904], [-72.92886, -9.04074], [-73.76576, -7.89884], [-73.65485, -7.77897], [-73.96938, -7.58465], [-73.77011, -7.28944], [-73.73986, -6.87919], [-73.12983, -6.43852], [-73.24579, -6.05764], [-72.83973, -5.14765], [-72.64391, -5.0391], [-71.87003, -4.51661], [-70.96814, -4.36915], [-70.77601, -4.15717], [-70.33236, -4.15214], [-70.19582, -4.3607], [-70.11305, -4.27281], [-70.00888, -4.37833], [-69.94708, -4.2431], [-70.3374, -3.79505], [-70.52393, -3.87553], [-70.71396, -3.7921], [-70.04609, -2.73906], [-70.94377, -2.23142], [-71.75223, -2.15058], [-72.92587, -2.44514], [-73.65312, -1.26222], [-74.26675, -0.97229]]]]
25722           }
25723         }, {
25724           type: "Feature",
25725           properties: {
25726             iso1A2: "PF",
25727             iso1A3: "PYF",
25728             iso1N3: "258",
25729             wikidata: "Q30971",
25730             nameEn: "French Polynesia",
25731             country: "FR",
25732             groups: ["Q1451600", "061", "009", "UN"],
25733             callingCodes: ["689"]
25734           },
25735           geometry: {
25736             type: "MultiPolygon",
25737             coordinates: [[[[-135.59706, -4.70473], [-156.48634, -15.52824], [-156.45576, -31.75456], [-133.59543, -28.4709], [-135.59706, -4.70473]]]]
25738           }
25739         }, {
25740           type: "Feature",
25741           properties: {
25742             iso1A2: "PG",
25743             iso1A3: "PNG",
25744             iso1N3: "598",
25745             wikidata: "Q691",
25746             nameEn: "Papua New Guinea",
25747             groups: ["054", "009", "UN"],
25748             driveSide: "left",
25749             callingCodes: ["675"]
25750           },
25751           geometry: {
25752             type: "MultiPolygon",
25753             coordinates: [[[[141.03157, 2.12829], [140.99813, -6.3233], [140.85295, -6.72996], [140.90448, -6.85033], [141.01763, -6.90181], [141.01842, -9.35091], [141.88934, -9.36111], [142.19246, -9.15378], [142.48658, -9.36754], [143.29772, -9.33993], [143.87386, -9.02382], [145.2855, -9.62524], [156.73836, -14.50464], [154.74815, -7.33315], [155.60735, -6.92266], [155.69784, -6.92661], [155.92557, -6.84664], [156.03993, -6.65703], [156.03296, -6.55528], [160.43769, -4.17974], [141.03157, 2.12829]]]]
25754           }
25755         }, {
25756           type: "Feature",
25757           properties: {
25758             iso1A2: "PH",
25759             iso1A3: "PHL",
25760             iso1N3: "608",
25761             wikidata: "Q928",
25762             nameEn: "Philippines",
25763             aliases: ["PI", "RP"],
25764             groups: ["035", "142", "UN"],
25765             callingCodes: ["63"]
25766           },
25767           geometry: {
25768             type: "MultiPolygon",
25769             coordinates: [[[[129.19694, 7.84182], [121.8109, 21.77688], [120.69238, 21.52331], [118.82252, 14.67191], [115.39742, 10.92666], [116.79524, 7.43869], [117.17735, 7.52841], [117.93857, 6.89845], [117.98544, 6.27477], [119.52945, 5.35672], [118.93936, 4.09009], [118.06469, 4.16638], [121.14448, 2.12444], [129.19694, 7.84182]]]]
25770           }
25771         }, {
25772           type: "Feature",
25773           properties: {
25774             iso1A2: "PK",
25775             iso1A3: "PAK",
25776             iso1N3: "586",
25777             wikidata: "Q843",
25778             nameEn: "Pakistan",
25779             groups: ["034", "142", "UN"],
25780             driveSide: "left",
25781             callingCodes: ["92"]
25782           },
25783           geometry: {
25784             type: "MultiPolygon",
25785             coordinates: [[[[75.72737, 36.7529], [75.45562, 36.71971], [75.40481, 36.95382], [75.13839, 37.02622], [74.56453, 37.03023], [74.53739, 36.96224], [74.43389, 37.00977], [74.04856, 36.82648], [73.82685, 36.91421], [72.6323, 36.84601], [72.18135, 36.71838], [71.80267, 36.49924], [71.60491, 36.39429], [71.19505, 36.04134], [71.37969, 35.95865], [71.55273, 35.71483], [71.49917, 35.6267], [71.65435, 35.4479], [71.54294, 35.31037], [71.5541, 35.28776], [71.67495, 35.21262], [71.52938, 35.09023], [71.55273, 35.02615], [71.49917, 35.00478], [71.50329, 34.97328], [71.29472, 34.87728], [71.28356, 34.80882], [71.08718, 34.69034], [71.11602, 34.63047], [71.0089, 34.54568], [71.02401, 34.44835], [71.17662, 34.36769], [71.12815, 34.26619], [71.13078, 34.16503], [71.09453, 34.13524], [71.09307, 34.11961], [71.06933, 34.10564], [71.07345, 34.06242], [70.88119, 33.97933], [70.54336, 33.9463], [69.90203, 34.04194], [69.87307, 33.9689], [69.85671, 33.93719], [70.00503, 33.73528], [70.14236, 33.71701], [70.14785, 33.6553], [70.20141, 33.64387], [70.17062, 33.53535], [70.32775, 33.34496], [70.13686, 33.21064], [70.07369, 33.22557], [70.02563, 33.14282], [69.85259, 33.09451], [69.79766, 33.13247], [69.71526, 33.09911], [69.57656, 33.09911], [69.49004, 33.01509], [69.49854, 32.88843], [69.5436, 32.8768], [69.47082, 32.85834], [69.38018, 32.76601], [69.43649, 32.7302], [69.44747, 32.6678], [69.38155, 32.56601], [69.2868, 32.53938], [69.23599, 32.45946], [69.27932, 32.29119], [69.27032, 32.14141], [69.3225, 31.93186], [69.20577, 31.85957], [69.11514, 31.70782], [69.00939, 31.62249], [68.95995, 31.64822], [68.91078, 31.59687], [68.79997, 31.61665], [68.6956, 31.75687], [68.57475, 31.83158], [68.44222, 31.76446], [68.27605, 31.75863], [68.25614, 31.80357], [68.1655, 31.82691], [68.00071, 31.6564], [67.86887, 31.63536], [67.72056, 31.52304], [67.58323, 31.52772], [67.62374, 31.40473], [67.7748, 31.4188], [67.78854, 31.33203], [67.29964, 31.19586], [67.03323, 31.24519], [67.04147, 31.31561], [66.83273, 31.26867], [66.72561, 31.20526], [66.68166, 31.07597], [66.58175, 30.97532], [66.42645, 30.95309], [66.39194, 30.9408], [66.28413, 30.57001], [66.34869, 30.404], [66.23609, 30.06321], [66.36042, 29.9583], [66.24175, 29.85181], [65.04005, 29.53957], [64.62116, 29.58903], [64.19796, 29.50407], [64.12966, 29.39157], [63.5876, 29.50456], [62.47751, 29.40782], [60.87231, 29.86514], [61.31508, 29.38903], [61.53765, 29.00507], [61.65978, 28.77937], [61.93581, 28.55284], [62.40259, 28.42703], [62.59499, 28.24842], [62.79412, 28.28108], [62.7638, 28.02992], [62.84905, 27.47627], [62.79684, 27.34381], [62.80604, 27.22412], [63.19649, 27.25674], [63.32283, 27.14437], [63.25005, 27.08692], [63.25005, 26.84212], [63.18688, 26.83844], [63.1889, 26.65072], [62.77352, 26.64099], [62.31484, 26.528], [62.21304, 26.26601], [62.05117, 26.31647], [61.89391, 26.26251], [61.83831, 26.07249], [61.83968, 25.7538], [61.683, 25.66638], [61.6433, 25.27541], [61.46682, 24.57869], [68.11329, 23.53945], [68.20763, 23.85849], [68.39339, 23.96838], [68.74643, 23.97027], [68.7416, 24.31904], [68.90914, 24.33156], [68.97781, 24.26021], [69.07806, 24.29777], [69.19341, 24.25646], [69.29778, 24.28712], [69.59579, 24.29777], [69.73335, 24.17007], [70.03428, 24.172], [70.11712, 24.30915], [70.5667, 24.43787], [70.57906, 24.27774], [70.71502, 24.23517], [70.88393, 24.27398], [70.85784, 24.30903], [70.94985, 24.3791], [71.04461, 24.34657], [71.12838, 24.42662], [71.00341, 24.46038], [70.97594, 24.60904], [71.09405, 24.69017], [70.94002, 24.92843], [70.89148, 25.15064], [70.66695, 25.39314], [70.67382, 25.68186], [70.60378, 25.71898], [70.53649, 25.68928], [70.37444, 25.67443], [70.2687, 25.71156], [70.0985, 25.93238], [70.08193, 26.08094], [70.17532, 26.24118], [70.17532, 26.55362], [70.05584, 26.60398], [69.88555, 26.56836], [69.50904, 26.74892], [69.58519, 27.18109], [70.03136, 27.56627], [70.12502, 27.8057], [70.37307, 28.01208], [70.60927, 28.02178], [70.79054, 27.68423], [71.89921, 27.96035], [71.9244, 28.11555], [72.20329, 28.3869], [72.29495, 28.66367], [72.40402, 28.78283], [72.94272, 29.02487], [73.01337, 29.16422], [73.05886, 29.1878], [73.28094, 29.56646], [73.3962, 29.94707], [73.58665, 30.01848], [73.80299, 30.06969], [73.97225, 30.19829], [73.95736, 30.28466], [73.88993, 30.36305], [74.5616, 31.04153], [74.67971, 31.05479], [74.6852, 31.12771], [74.60006, 31.13711], [74.60281, 31.10419], [74.56023, 31.08303], [74.51629, 31.13829], [74.53223, 31.30321], [74.59773, 31.4136], [74.64713, 31.45605], [74.59319, 31.50197], [74.61517, 31.55698], [74.57498, 31.60382], [74.47771, 31.72227], [74.58907, 31.87824], [74.79919, 31.95983], [74.86236, 32.04485], [74.9269, 32.0658], [75.00793, 32.03786], [75.25649, 32.10187], [75.38046, 32.26836], [75.28259, 32.36556], [75.03265, 32.49538], [74.97634, 32.45367], [74.84725, 32.49075], [74.68362, 32.49298], [74.67431, 32.56676], [74.65251, 32.56416], [74.64424, 32.60985], [74.69542, 32.66792], [74.65345, 32.71225], [74.7113, 32.84219], [74.64675, 32.82604], [74.6289, 32.75561], [74.45312, 32.77755], [74.41467, 32.90563], [74.31227, 32.92795], [74.34875, 32.97823], [74.31854, 33.02891], [74.17571, 33.07495], [74.15374, 33.13477], [74.02144, 33.18908], [74.01366, 33.25199], [74.08782, 33.26232], [74.17983, 33.3679], [74.18121, 33.4745], [74.10115, 33.56392], [74.03576, 33.56718], [73.97367, 33.64061], [73.98968, 33.66155], [73.96423, 33.73071], [74.00891, 33.75437], [74.05898, 33.82089], [74.14001, 33.83002], [74.26086, 33.92237], [74.25262, 34.01577], [74.21554, 34.03853], [73.91341, 34.01235], [73.88732, 34.05105], [73.90677, 34.10504], [73.98208, 34.2522], [73.90517, 34.35317], [73.8475, 34.32935], [73.74862, 34.34183], [73.74999, 34.3781], [73.88732, 34.48911], [73.89419, 34.54568], [73.93951, 34.57169], [73.93401, 34.63386], [73.96423, 34.68244], [74.12897, 34.70073], [74.31239, 34.79626], [74.58083, 34.77386], [74.6663, 34.703], [75.01479, 34.64629], [75.38009, 34.55021], [75.75438, 34.51827], [76.04614, 34.67566], [76.15463, 34.6429], [76.47186, 34.78965], [76.67648, 34.76371], [76.74377, 34.84039], [76.74514, 34.92488], [76.87193, 34.96906], [76.99251, 34.93349], [77.11796, 35.05419], [76.93465, 35.39866], [76.85088, 35.39754], [76.75475, 35.52617], [76.77323, 35.66062], [76.50961, 35.8908], [76.33453, 35.84296], [76.14913, 35.82848], [76.15325, 35.9264], [75.93028, 36.13136], [76.00906, 36.17511], [76.0324, 36.41198], [75.92391, 36.56986], [75.72737, 36.7529]]]]
25786           }
25787         }, {
25788           type: "Feature",
25789           properties: {
25790             iso1A2: "PL",
25791             iso1A3: "POL",
25792             iso1N3: "616",
25793             wikidata: "Q36",
25794             nameEn: "Poland",
25795             groups: ["EU", "151", "150", "UN"],
25796             callingCodes: ["48"]
25797           },
25798           geometry: {
25799             type: "MultiPolygon",
25800             coordinates: [[[[18.57853, 55.25302], [14.20811, 54.12784], [14.22634, 53.9291], [14.20647, 53.91671], [14.18544, 53.91258], [14.20823, 53.90776], [14.21323, 53.8664], [14.27249, 53.74464], [14.26782, 53.69866], [14.2836, 53.67721], [14.27133, 53.66613], [14.28477, 53.65955], [14.2853, 53.63392], [14.31904, 53.61581], [14.30416, 53.55499], [14.3273, 53.50587], [14.35209, 53.49506], [14.4215, 53.27724], [14.44133, 53.27427], [14.45125, 53.26241], [14.40662, 53.21098], [14.37853, 53.20405], [14.36696, 53.16444], [14.38679, 53.13669], [14.35044, 53.05829], [14.25954, 53.00264], [14.14056, 52.95786], [14.15873, 52.87715], [14.12256, 52.84311], [14.13806, 52.82392], [14.22071, 52.81175], [14.61073, 52.59847], [14.6289, 52.57136], [14.60081, 52.53116], [14.63056, 52.48993], [14.54423, 52.42568], [14.55228, 52.35264], [14.56378, 52.33838], [14.58149, 52.28007], [14.70139, 52.25038], [14.71319, 52.22144], [14.68344, 52.19612], [14.70616, 52.16927], [14.67683, 52.13936], [14.6917, 52.10283], [14.72971, 52.09167], [14.76026, 52.06624], [14.71339, 52.00337], [14.70488, 51.97679], [14.7139, 51.95643], [14.71836, 51.95606], [14.72163, 51.95188], [14.7177, 51.94048], [14.70601, 51.92944], [14.6933, 51.9044], [14.6588, 51.88359], [14.59089, 51.83302], [14.60493, 51.80473], [14.64625, 51.79472], [14.66386, 51.73282], [14.69065, 51.70842], [14.75392, 51.67445], [14.75759, 51.62318], [14.7727, 51.61263], [14.71125, 51.56209], [14.73047, 51.54606], [14.72652, 51.53902], [14.73219, 51.52922], [14.94749, 51.47155], [14.9652, 51.44793], [14.96899, 51.38367], [14.98008, 51.33449], [15.04288, 51.28387], [15.01242, 51.21285], [15.0047, 51.16874], [14.99311, 51.16249], [14.99414, 51.15813], [15.00083, 51.14974], [14.99646, 51.14365], [14.99079, 51.14284], [14.99689, 51.12205], [14.98229, 51.11354], [14.97938, 51.07742], [14.95529, 51.04552], [14.92942, 50.99744], [14.89252, 50.94999], [14.89681, 50.9422], [14.81664, 50.88148], [14.82803, 50.86966], [14.99852, 50.86817], [15.01088, 50.97984], [14.96419, 50.99108], [15.02433, 51.0242], [15.03895, 51.0123], [15.06218, 51.02269], [15.10152, 51.01095], [15.11937, 50.99021], [15.16744, 51.01959], [15.1743, 50.9833], [15.2361, 50.99886], [15.27043, 50.97724], [15.2773, 50.8907], [15.36656, 50.83956], [15.3803, 50.77187], [15.43798, 50.80833], [15.73186, 50.73885], [15.81683, 50.75666], [15.87331, 50.67188], [15.97219, 50.69799], [16.0175, 50.63009], [15.98317, 50.61528], [16.02437, 50.60046], [16.10265, 50.66405], [16.20839, 50.63096], [16.23174, 50.67101], [16.33611, 50.66579], [16.44597, 50.58041], [16.34572, 50.49575], [16.31413, 50.50274], [16.19526, 50.43291], [16.21585, 50.40627], [16.22821, 50.41054], [16.28118, 50.36891], [16.30289, 50.38292], [16.36495, 50.37679], [16.3622, 50.34875], [16.39379, 50.3207], [16.42674, 50.32509], [16.56407, 50.21009], [16.55446, 50.16613], [16.63137, 50.1142], [16.7014, 50.09659], [16.8456, 50.20834], [16.98018, 50.24172], [17.00353, 50.21449], [17.02825, 50.23118], [16.99803, 50.25753], [17.02138, 50.27772], [16.99803, 50.30316], [16.94448, 50.31281], [16.90877, 50.38642], [16.85933, 50.41093], [16.89229, 50.45117], [17.1224, 50.39494], [17.14498, 50.38117], [17.19579, 50.38817], [17.19991, 50.3654], [17.27681, 50.32246], [17.34273, 50.32947], [17.34548, 50.2628], [17.3702, 50.28123], [17.58889, 50.27837], [17.67764, 50.28977], [17.69292, 50.32859], [17.74648, 50.29966], [17.72176, 50.25665], [17.76296, 50.23382], [17.70528, 50.18812], [17.59404, 50.16437], [17.66683, 50.10275], [17.6888, 50.12037], [17.7506, 50.07896], [17.77669, 50.02253], [17.86886, 49.97452], [18.00191, 50.01723], [18.04585, 50.01194], [18.04585, 50.03311], [18.00396, 50.04954], [18.03212, 50.06574], [18.07898, 50.04535], [18.10628, 50.00223], [18.20241, 49.99958], [18.21752, 49.97309], [18.27107, 49.96779], [18.27794, 49.93863], [18.31914, 49.91565], [18.33278, 49.92415], [18.33562, 49.94747], [18.41604, 49.93498], [18.53423, 49.89906], [18.54495, 49.9079], [18.54299, 49.92537], [18.57697, 49.91565], [18.57045, 49.87849], [18.60341, 49.86256], [18.57183, 49.83334], [18.61278, 49.7618], [18.61368, 49.75426], [18.62645, 49.75002], [18.62943, 49.74603], [18.62676, 49.71983], [18.69817, 49.70473], [18.72838, 49.68163], [18.80479, 49.6815], [18.84786, 49.5446], [18.84521, 49.51672], [18.94536, 49.52143], [18.97283, 49.49914], [18.9742, 49.39557], [19.18019, 49.41165], [19.25435, 49.53391], [19.36009, 49.53747], [19.37795, 49.574], [19.45348, 49.61583], [19.52626, 49.57311], [19.53313, 49.52856], [19.57845, 49.46077], [19.64162, 49.45184], [19.6375, 49.40897], [19.72127, 49.39288], [19.78581, 49.41701], [19.82237, 49.27806], [19.75286, 49.20751], [19.86409, 49.19316], [19.90529, 49.23532], [19.98494, 49.22904], [20.08238, 49.1813], [20.13738, 49.31685], [20.21977, 49.35265], [20.31453, 49.34817], [20.31728, 49.39914], [20.39939, 49.3896], [20.46422, 49.41612], [20.5631, 49.375], [20.61666, 49.41791], [20.72274, 49.41813], [20.77971, 49.35383], [20.9229, 49.29626], [20.98733, 49.30774], [21.09799, 49.37176], [21.041, 49.41791], [21.12477, 49.43666], [21.19756, 49.4054], [21.27858, 49.45988], [21.43376, 49.41433], [21.62328, 49.4447], [21.77983, 49.35443], [21.82927, 49.39467], [21.96385, 49.3437], [22.04427, 49.22136], [22.56155, 49.08865], [22.89122, 49.00725], [22.86336, 49.10513], [22.72009, 49.20288], [22.748, 49.32759], [22.69444, 49.49378], [22.64534, 49.53094], [22.78304, 49.65543], [22.80261, 49.69098], [22.83179, 49.69875], [22.99329, 49.84249], [23.28221, 50.0957], [23.67635, 50.33385], [23.71382, 50.38248], [23.79445, 50.40481], [23.99563, 50.41289], [24.03668, 50.44507], [24.07048, 50.5071], [24.0996, 50.60752], [24.0595, 50.71625], [23.95925, 50.79271], [23.99254, 50.83847], [24.0952, 50.83262], [24.14524, 50.86128], [24.04576, 50.90196], [23.92217, 51.00836], [23.90376, 51.07697], [23.80678, 51.18405], [23.63858, 51.32182], [23.69905, 51.40871], [23.62751, 51.50512], [23.56236, 51.53673], [23.57053, 51.55938], [23.53198, 51.74298], [23.62691, 51.78208], [23.61523, 51.92066], [23.68733, 51.9906], [23.64066, 52.07626], [23.61, 52.11264], [23.54314, 52.12148], [23.47859, 52.18215], [23.20071, 52.22848], [23.18196, 52.28812], [23.34141, 52.44845], [23.45112, 52.53774], [23.58296, 52.59868], [23.73615, 52.6149], [23.93763, 52.71332], [23.91805, 52.94016], [23.94689, 52.95919], [23.92184, 53.02079], [23.87548, 53.0831], [23.91393, 53.16469], [23.85657, 53.22923], [23.81995, 53.24131], [23.62004, 53.60942], [23.51284, 53.95052], [23.48261, 53.98855], [23.52702, 54.04622], [23.49196, 54.14764], [23.45223, 54.17775], [23.42418, 54.17911], [23.39525, 54.21672], [23.3494, 54.25155], [23.24656, 54.25701], [23.15938, 54.29894], [23.15526, 54.31076], [23.13905, 54.31567], [23.104, 54.29794], [23.04323, 54.31567], [23.05726, 54.34565], [22.99649, 54.35927], [23.00584, 54.38514], [22.83756, 54.40827], [22.79705, 54.36264], [21.41123, 54.32395], [20.63871, 54.3706], [19.8038, 54.44203], [19.64312, 54.45423], [18.57853, 55.25302]]]]
25801           }
25802         }, {
25803           type: "Feature",
25804           properties: {
25805             iso1A2: "PM",
25806             iso1A3: "SPM",
25807             iso1N3: "666",
25808             wikidata: "Q34617",
25809             nameEn: "Saint Pierre and Miquelon",
25810             country: "FR",
25811             groups: ["Q1451600", "021", "003", "019", "UN"],
25812             callingCodes: ["508"]
25813           },
25814           geometry: {
25815             type: "MultiPolygon",
25816             coordinates: [[[[-56.72993, 46.65575], [-55.90758, 46.6223], [-56.27503, 47.39728], [-56.72993, 46.65575]]]]
25817           }
25818         }, {
25819           type: "Feature",
25820           properties: {
25821             iso1A2: "PN",
25822             iso1A3: "PCN",
25823             iso1N3: "612",
25824             wikidata: "Q35672",
25825             nameEn: "Pitcairn Islands",
25826             country: "GB",
25827             groups: ["BOTS", "061", "009", "UN"],
25828             driveSide: "left",
25829             callingCodes: ["64"]
25830           },
25831           geometry: {
25832             type: "MultiPolygon",
25833             coordinates: [[[[-133.59543, -28.4709], [-122.0366, -24.55017], [-133.61511, -21.93325], [-133.59543, -28.4709]]]]
25834           }
25835         }, {
25836           type: "Feature",
25837           properties: {
25838             iso1A2: "PR",
25839             iso1A3: "PRI",
25840             iso1N3: "630",
25841             wikidata: "Q1183",
25842             nameEn: "Puerto Rico",
25843             aliases: ["US-PR"],
25844             country: "US",
25845             groups: ["Q1352230", "029", "003", "419", "019", "UN"],
25846             roadSpeedUnit: "mph",
25847             callingCodes: ["1 787", "1 939"]
25848           },
25849           geometry: {
25850             type: "MultiPolygon",
25851             coordinates: [[[[-65.27974, 17.56928], [-65.02435, 18.73231], [-67.99519, 18.97186], [-68.23894, 17.84663], [-65.27974, 17.56928]]]]
25852           }
25853         }, {
25854           type: "Feature",
25855           properties: {
25856             iso1A2: "PS",
25857             iso1A3: "PSE",
25858             iso1N3: "275",
25859             wikidata: "Q219060",
25860             nameEn: "Palestine"
25861           },
25862           geometry: null
25863         }, {
25864           type: "Feature",
25865           properties: {
25866             iso1A2: "PT",
25867             iso1A3: "PRT",
25868             iso1N3: "620",
25869             wikidata: "Q45",
25870             nameEn: "Portugal"
25871           },
25872           geometry: null
25873         }, {
25874           type: "Feature",
25875           properties: {
25876             iso1A2: "PW",
25877             iso1A3: "PLW",
25878             iso1N3: "585",
25879             wikidata: "Q695",
25880             nameEn: "Palau",
25881             groups: ["057", "009", "UN"],
25882             roadSpeedUnit: "mph",
25883             callingCodes: ["680"]
25884           },
25885           geometry: {
25886             type: "MultiPolygon",
25887             coordinates: [[[[128.97621, 3.08804], [136.39296, 1.54187], [136.04605, 12.45908], [128.97621, 3.08804]]]]
25888           }
25889         }, {
25890           type: "Feature",
25891           properties: {
25892             iso1A2: "PY",
25893             iso1A3: "PRY",
25894             iso1N3: "600",
25895             wikidata: "Q733",
25896             nameEn: "Paraguay",
25897             groups: ["005", "419", "019", "UN"],
25898             callingCodes: ["595"]
25899           },
25900           geometry: {
25901             type: "MultiPolygon",
25902             coordinates: [[[[-58.16225, -20.16193], [-58.23216, -19.80058], [-59.06965, -19.29148], [-60.00638, -19.2981], [-61.73723, -19.63958], [-61.93912, -20.10053], [-62.26883, -20.55311], [-62.2757, -21.06657], [-62.64455, -22.25091], [-62.51761, -22.37684], [-62.22768, -22.55807], [-61.9756, -23.0507], [-61.0782, -23.62932], [-60.99754, -23.80934], [-60.28163, -24.04436], [-60.03367, -24.00701], [-59.45482, -24.34787], [-59.33886, -24.49935], [-58.33055, -24.97099], [-58.25492, -24.92528], [-57.80821, -25.13863], [-57.57431, -25.47269], [-57.87176, -25.93604], [-58.1188, -26.16704], [-58.3198, -26.83443], [-58.65321, -27.14028], [-58.59549, -27.29973], [-58.04205, -27.2387], [-56.85337, -27.5165], [-56.18313, -27.29851], [-55.89195, -27.3467], [-55.74475, -27.44485], [-55.59094, -27.32444], [-55.62322, -27.1941], [-55.39611, -26.97679], [-55.25243, -26.93808], [-55.16948, -26.96068], [-55.06351, -26.80195], [-55.00584, -26.78754], [-54.80868, -26.55669], [-54.70732, -26.45099], [-54.69333, -26.37705], [-54.67359, -25.98607], [-54.60664, -25.9691], [-54.62063, -25.91213], [-54.59398, -25.59224], [-54.59509, -25.53696], [-54.60196, -25.48397], [-54.62033, -25.46026], [-54.4423, -25.13381], [-54.28207, -24.07305], [-54.32807, -24.01865], [-54.6238, -23.83078], [-55.02691, -23.97317], [-55.0518, -23.98666], [-55.12292, -23.99669], [-55.41784, -23.9657], [-55.44117, -23.9185], [-55.43585, -23.87157], [-55.5555, -23.28237], [-55.52288, -23.2595], [-55.5446, -23.22811], [-55.63849, -22.95122], [-55.62493, -22.62765], [-55.68742, -22.58407], [-55.6986, -22.56268], [-55.72366, -22.5519], [-55.741, -22.52018], [-55.74941, -22.46436], [-55.8331, -22.29008], [-56.23206, -22.25347], [-56.45893, -22.08072], [-56.5212, -22.11556], [-56.6508, -22.28387], [-57.98625, -22.09157], [-57.94642, -21.73799], [-57.88239, -21.6868], [-57.93492, -21.65505], [-57.84536, -20.93155], [-58.16225, -20.16193]]]]
25903           }
25904         }, {
25905           type: "Feature",
25906           properties: {
25907             iso1A2: "QA",
25908             iso1A3: "QAT",
25909             iso1N3: "634",
25910             wikidata: "Q846",
25911             nameEn: "Qatar",
25912             groups: ["145", "142", "UN"],
25913             callingCodes: ["974"]
25914           },
25915           geometry: {
25916             type: "MultiPolygon",
25917             coordinates: [[[[50.92992, 24.54396], [51.09638, 24.46907], [51.29972, 24.50747], [51.39468, 24.62785], [51.58834, 24.66608], [51.83108, 24.71675], [51.83682, 26.70231], [50.93865, 26.30758], [50.81266, 25.88946], [50.86149, 25.6965], [50.7801, 25.595], [50.80824, 25.54641], [50.57069, 25.57887], [50.8133, 24.74049], [50.92992, 24.54396]]]]
25918           }
25919         }, {
25920           type: "Feature",
25921           properties: {
25922             iso1A2: "RE",
25923             iso1A3: "REU",
25924             iso1N3: "638",
25925             wikidata: "Q17070",
25926             nameEn: "R\xE9union",
25927             country: "FR",
25928             groups: ["Q3320166", "EU", "014", "202", "002", "UN"],
25929             callingCodes: ["262"]
25930           },
25931           geometry: {
25932             type: "MultiPolygon",
25933             coordinates: [[[[53.37984, -21.23941], [56.73473, -21.9174], [56.62373, -20.2711], [53.37984, -21.23941]]]]
25934           }
25935         }, {
25936           type: "Feature",
25937           properties: {
25938             iso1A2: "RO",
25939             iso1A3: "ROU",
25940             iso1N3: "642",
25941             wikidata: "Q218",
25942             nameEn: "Romania",
25943             groups: ["EU", "151", "150", "UN"],
25944             callingCodes: ["40"]
25945           },
25946           geometry: {
25947             type: "MultiPolygon",
25948             coordinates: [[[[27.15622, 47.98538], [27.02985, 48.09083], [27.04118, 48.12522], [26.96119, 48.13003], [26.98042, 48.15752], [26.94265, 48.1969], [26.87708, 48.19919], [26.81161, 48.25049], [26.62823, 48.25804], [26.55202, 48.22445], [26.33504, 48.18418], [26.17711, 47.99246], [26.05901, 47.9897], [25.77723, 47.93919], [25.63878, 47.94924], [25.23778, 47.89403], [25.11144, 47.75203], [24.88896, 47.7234], [24.81893, 47.82031], [24.70632, 47.84428], [24.61994, 47.95062], [24.43578, 47.97131], [24.34926, 47.9244], [24.22566, 47.90231], [24.11281, 47.91487], [24.06466, 47.95317], [24.02999, 47.95087], [24.00801, 47.968], [23.98553, 47.96076], [23.96337, 47.96672], [23.94192, 47.94868], [23.89352, 47.94512], [23.8602, 47.9329], [23.80904, 47.98142], [23.75188, 47.99705], [23.66262, 47.98786], [23.63894, 48.00293], [23.5653, 48.00499], [23.52803, 48.01818], [23.4979, 47.96858], [23.33577, 48.0237], [23.27397, 48.08245], [23.15999, 48.12188], [23.1133, 48.08061], [23.08858, 48.00716], [23.0158, 47.99338], [22.92241, 48.02002], [22.94301, 47.96672], [22.89849, 47.95851], [22.77991, 47.87211], [22.76617, 47.8417], [22.67247, 47.7871], [22.46559, 47.76583], [22.41979, 47.7391], [22.31816, 47.76126], [22.00917, 47.50492], [22.03389, 47.42508], [22.01055, 47.37767], [21.94463, 47.38046], [21.78395, 47.11104], [21.648, 47.03902], [21.68645, 46.99595], [21.59581, 46.91628], [21.59307, 46.86935], [21.52028, 46.84118], [21.48935, 46.7577], [21.5151, 46.72147], [21.43926, 46.65109], [21.33214, 46.63035], [21.26929, 46.4993], [21.28061, 46.44941], [21.16872, 46.30118], [21.06572, 46.24897], [20.86797, 46.28884], [20.74574, 46.25467], [20.76085, 46.21002], [20.63863, 46.12728], [20.49718, 46.18721], [20.45377, 46.14405], [20.35573, 46.16629], [20.28324, 46.1438], [20.26068, 46.12332], [20.35862, 45.99356], [20.54818, 45.89939], [20.65645, 45.82801], [20.70069, 45.7493], [20.77416, 45.75601], [20.78446, 45.78522], [20.82364, 45.77738], [20.80361, 45.65875], [20.76798, 45.60969], [20.83321, 45.53567], [20.77217, 45.49788], [20.86026, 45.47295], [20.87948, 45.42743], [21.09894, 45.30144], [21.17612, 45.32566], [21.20392, 45.2677], [21.29398, 45.24148], [21.48278, 45.19557], [21.51299, 45.15345], [21.4505, 45.04294], [21.35855, 45.01941], [21.54938, 44.9327], [21.56328, 44.89502], [21.48202, 44.87199], [21.44013, 44.87613], [21.35643, 44.86364], [21.38802, 44.78133], [21.55007, 44.77304], [21.60019, 44.75208], [21.61942, 44.67059], [21.67504, 44.67107], [21.71692, 44.65349], [21.7795, 44.66165], [21.99364, 44.63395], [22.08016, 44.49844], [22.13234, 44.47444], [22.18315, 44.48179], [22.30844, 44.6619], [22.45301, 44.7194], [22.61917, 44.61489], [22.69196, 44.61587], [22.76749, 44.54446], [22.70981, 44.51852], [22.61368, 44.55719], [22.56493, 44.53419], [22.54021, 44.47836], [22.45436, 44.47258], [22.56012, 44.30712], [22.68166, 44.28206], [22.67173, 44.21564], [23.04988, 44.07694], [23.01674, 44.01946], [22.87873, 43.9844], [22.83753, 43.88055], [22.85314, 43.84452], [23.05288, 43.79494], [23.26772, 43.84843], [23.4507, 43.84936], [23.61687, 43.79289], [23.73978, 43.80627], [24.18149, 43.68218], [24.35364, 43.70211], [24.50264, 43.76314], [24.62281, 43.74082], [24.73542, 43.68523], [24.96682, 43.72693], [25.10718, 43.6831], [25.17144, 43.70261], [25.39528, 43.61866], [25.72792, 43.69263], [25.94911, 43.85745], [26.05584, 43.90925], [26.10115, 43.96908], [26.38764, 44.04356], [26.62712, 44.05698], [26.95141, 44.13555], [27.26845, 44.12602], [27.39757, 44.0141], [27.60834, 44.01206], [27.64542, 44.04958], [27.73468, 43.95326], [27.92008, 44.00761], [27.99558, 43.84193], [28.23293, 43.76], [29.24336, 43.70874], [30.04414, 45.08461], [29.69272, 45.19227], [29.65428, 45.25629], [29.68175, 45.26885], [29.59798, 45.38857], [29.42632, 45.44545], [29.24779, 45.43388], [28.96077, 45.33164], [28.94292, 45.28045], [28.81383, 45.3384], [28.78911, 45.24179], [28.71358, 45.22631], [28.5735, 45.24759], [28.34554, 45.32102], [28.28504, 45.43907], [28.21139, 45.46895], [28.18741, 45.47358], [28.08927, 45.6051], [28.16568, 45.6421], [28.13111, 45.92819], [28.08612, 46.01105], [28.13684, 46.18099], [28.10937, 46.22852], [28.19864, 46.31869], [28.18902, 46.35283], [28.25769, 46.43334], [28.22281, 46.50481], [28.24808, 46.64305], [28.12173, 46.82283], [28.09095, 46.97621], [27.81892, 47.1381], [27.73172, 47.29248], [27.68706, 47.28962], [27.60263, 47.32507], [27.55731, 47.46637], [27.47942, 47.48113], [27.3979, 47.59473], [27.32202, 47.64009], [27.25519, 47.71366], [27.29069, 47.73722], [27.1618, 47.92391], [27.15622, 47.98538]]]]
25949           }
25950         }, {
25951           type: "Feature",
25952           properties: {
25953             iso1A2: "RS",
25954             iso1A3: "SRB",
25955             iso1N3: "688",
25956             wikidata: "Q403",
25957             nameEn: "Serbia",
25958             groups: ["039", "150", "UN"],
25959             callingCodes: ["381"]
25960           },
25961           geometry: {
25962             type: "MultiPolygon",
25963             coordinates: [[[[19.66007, 46.19005], [19.56113, 46.16824], [19.52473, 46.1171], [19.28826, 45.99694], [19.14543, 45.9998], [19.10388, 46.04015], [19.0791, 45.96458], [19.01284, 45.96529], [18.99712, 45.93537], [18.81394, 45.91329], [18.85783, 45.85493], [18.90305, 45.71863], [18.96691, 45.66731], [18.88776, 45.57253], [18.94562, 45.53712], [19.07471, 45.53086], [19.08364, 45.48804], [18.99918, 45.49333], [18.97446, 45.37528], [19.10774, 45.29547], [19.28208, 45.23813], [19.41941, 45.23475], [19.43589, 45.17137], [19.19144, 45.17863], [19.14063, 45.12972], [19.07952, 45.14668], [19.1011, 45.01191], [19.05205, 44.97692], [19.15573, 44.95409], [19.06853, 44.89915], [19.02871, 44.92541], [18.98957, 44.90645], [19.01994, 44.85493], [19.18183, 44.92055], [19.36722, 44.88164], [19.32543, 44.74058], [19.26388, 44.65412], [19.16699, 44.52197], [19.13369, 44.52521], [19.12278, 44.50132], [19.14837, 44.45253], [19.14681, 44.41463], [19.11785, 44.40313], [19.10749, 44.39421], [19.10704, 44.38249], [19.10365, 44.37795], [19.10298, 44.36924], [19.11865, 44.36712], [19.1083, 44.3558], [19.11547, 44.34218], [19.13556, 44.338], [19.13332, 44.31492], [19.16741, 44.28648], [19.18328, 44.28383], [19.20508, 44.2917], [19.23306, 44.26097], [19.26945, 44.26957], [19.32464, 44.27185], [19.34773, 44.23244], [19.3588, 44.18353], [19.40927, 44.16722], [19.43905, 44.13088], [19.47338, 44.15034], [19.48386, 44.14332], [19.47321, 44.1193], [19.51167, 44.08158], [19.55999, 44.06894], [19.57467, 44.04716], [19.61991, 44.05254], [19.61836, 44.01464], [19.56498, 43.99922], [19.52515, 43.95573], [19.38439, 43.96611], [19.24363, 44.01502], [19.23465, 43.98764], [19.3986, 43.79668], [19.5176, 43.71403], [19.50455, 43.58385], [19.42696, 43.57987], [19.41941, 43.54056], [19.36653, 43.60921], [19.33426, 43.58833], [19.2553, 43.5938], [19.24774, 43.53061], [19.22807, 43.5264], [19.22229, 43.47926], [19.44315, 43.38846], [19.48171, 43.32644], [19.52962, 43.31623], [19.54598, 43.25158], [19.62661, 43.2286], [19.64063, 43.19027], [19.76918, 43.16044], [19.79255, 43.11951], [19.92576, 43.08539], [19.96549, 43.11098], [19.98887, 43.0538], [20.04729, 43.02732], [20.05431, 42.99571], [20.12325, 42.96237], [20.14896, 42.99058], [20.16415, 42.97177], [20.34528, 42.90676], [20.35692, 42.8335], [20.40594, 42.84853], [20.43734, 42.83157], [20.53484, 42.8885], [20.48692, 42.93208], [20.59929, 43.01067], [20.64557, 43.00826], [20.69515, 43.09641], [20.59929, 43.20492], [20.68688, 43.21335], [20.73811, 43.25068], [20.82145, 43.26769], [20.88685, 43.21697], [20.83727, 43.17842], [20.96287, 43.12416], [21.00749, 43.13984], [21.05378, 43.10707], [21.08952, 43.13471], [21.14465, 43.11089], [21.16734, 42.99694], [21.2041, 43.02277], [21.23877, 43.00848], [21.23534, 42.95523], [21.2719, 42.8994], [21.32974, 42.90424], [21.36941, 42.87397], [21.44047, 42.87276], [21.39045, 42.74888], [21.47498, 42.74695], [21.59154, 42.72643], [21.58755, 42.70418], [21.6626, 42.67813], [21.75025, 42.70125], [21.79413, 42.65923], [21.75672, 42.62695], [21.7327, 42.55041], [21.70522, 42.54176], [21.7035, 42.51899], [21.62556, 42.45106], [21.64209, 42.41081], [21.62887, 42.37664], [21.59029, 42.38042], [21.57021, 42.3647], [21.53467, 42.36809], [21.5264, 42.33634], [21.56772, 42.30946], [21.58992, 42.25915], [21.70111, 42.23789], [21.77176, 42.2648], [21.84654, 42.3247], [21.91595, 42.30392], [21.94405, 42.34669], [22.02908, 42.29848], [22.16384, 42.32103], [22.29605, 42.37477], [22.29275, 42.34913], [22.34773, 42.31725], [22.45919, 42.33822], [22.47498, 42.3915], [22.51961, 42.3991], [22.55669, 42.50144], [22.43983, 42.56851], [22.4997, 42.74144], [22.43309, 42.82057], [22.54302, 42.87774], [22.74826, 42.88701], [22.78397, 42.98253], [22.89521, 43.03625], [22.98104, 43.11199], [23.00806, 43.19279], [22.89727, 43.22417], [22.82036, 43.33665], [22.53397, 43.47225], [22.47582, 43.6558], [22.41043, 43.69566], [22.35558, 43.81281], [22.41449, 44.00514], [22.61688, 44.06534], [22.61711, 44.16938], [22.67173, 44.21564], [22.68166, 44.28206], [22.56012, 44.30712], [22.45436, 44.47258], [22.54021, 44.47836], [22.56493, 44.53419], [22.61368, 44.55719], [22.70981, 44.51852], [22.76749, 44.54446], [22.69196, 44.61587], [22.61917, 44.61489], [22.45301, 44.7194], [22.30844, 44.6619], [22.18315, 44.48179], [22.13234, 44.47444], [22.08016, 44.49844], [21.99364, 44.63395], [21.7795, 44.66165], [21.71692, 44.65349], [21.67504, 44.67107], [21.61942, 44.67059], [21.60019, 44.75208], [21.55007, 44.77304], [21.38802, 44.78133], [21.35643, 44.86364], [21.44013, 44.87613], [21.48202, 44.87199], [21.56328, 44.89502], [21.54938, 44.9327], [21.35855, 45.01941], [21.4505, 45.04294], [21.51299, 45.15345], [21.48278, 45.19557], [21.29398, 45.24148], [21.20392, 45.2677], [21.17612, 45.32566], [21.09894, 45.30144], [20.87948, 45.42743], [20.86026, 45.47295], [20.77217, 45.49788], [20.83321, 45.53567], [20.76798, 45.60969], [20.80361, 45.65875], [20.82364, 45.77738], [20.78446, 45.78522], [20.77416, 45.75601], [20.70069, 45.7493], [20.65645, 45.82801], [20.54818, 45.89939], [20.35862, 45.99356], [20.26068, 46.12332], [20.09713, 46.17315], [20.03533, 46.14509], [20.01816, 46.17696], [19.93508, 46.17553], [19.81491, 46.1313], [19.66007, 46.19005]]]]
25964           }
25965         }, {
25966           type: "Feature",
25967           properties: {
25968             iso1A2: "RU",
25969             iso1A3: "RUS",
25970             iso1N3: "643",
25971             wikidata: "Q159",
25972             nameEn: "Russia"
25973           },
25974           geometry: null
25975         }, {
25976           type: "Feature",
25977           properties: {
25978             iso1A2: "RW",
25979             iso1A3: "RWA",
25980             iso1N3: "646",
25981             wikidata: "Q1037",
25982             nameEn: "Rwanda",
25983             groups: ["014", "202", "002", "UN"],
25984             callingCodes: ["250"]
25985           },
25986           geometry: {
25987             type: "MultiPolygon",
25988             coordinates: [[[[30.47194, -1.0555], [30.35212, -1.06896], [30.16369, -1.34303], [29.912, -1.48269], [29.82657, -1.31187], [29.59061, -1.39016], [29.53062, -1.40499], [29.45038, -1.5054], [29.36322, -1.50887], [29.24323, -1.66826], [29.24458, -1.69663], [29.11847, -1.90576], [29.17562, -2.12278], [29.105, -2.27043], [29.00051, -2.29001], [28.95642, -2.37321], [28.89601, -2.37321], [28.86826, -2.41888], [28.86846, -2.44866], [28.89132, -2.47557], [28.89342, -2.49017], [28.88846, -2.50493], [28.87497, -2.50887], [28.86209, -2.5231], [28.86193, -2.53185], [28.87943, -2.55165], [28.89288, -2.55848], [28.90226, -2.62385], [28.89793, -2.66111], [28.94346, -2.69124], [29.00357, -2.70596], [29.04081, -2.7416], [29.0562, -2.58632], [29.32234, -2.6483], [29.36805, -2.82933], [29.88237, -2.75105], [29.95911, -2.33348], [30.14034, -2.43626], [30.42933, -2.31064], [30.54501, -2.41404], [30.83915, -2.35795], [30.89303, -2.08223], [30.80802, -1.91477], [30.84079, -1.64652], [30.71974, -1.43244], [30.57123, -1.33264], [30.50889, -1.16412], [30.45116, -1.10641], [30.47194, -1.0555]]]]
25989           }
25990         }, {
25991           type: "Feature",
25992           properties: {
25993             iso1A2: "SA",
25994             iso1A3: "SAU",
25995             iso1N3: "682",
25996             wikidata: "Q851",
25997             nameEn: "Saudi Arabia",
25998             groups: ["145", "142", "UN"],
25999             callingCodes: ["966"]
26000           },
26001           geometry: {
26002             type: "MultiPolygon",
26003             coordinates: [[[[40.01521, 32.05667], [39.29903, 32.23259], [38.99233, 31.99721], [36.99791, 31.50081], [37.99354, 30.49998], [37.66395, 30.33245], [37.4971, 29.99949], [36.75083, 29.86903], [36.50005, 29.49696], [36.07081, 29.18469], [34.8812, 29.36878], [34.4454, 27.91479], [37.8565, 22.00903], [39.63762, 18.37348], [40.99158, 15.81743], [42.15205, 16.40211], [42.76801, 16.40371], [42.94625, 16.39721], [42.94351, 16.49467], [42.97215, 16.51093], [43.11601, 16.53166], [43.15274, 16.67248], [43.22066, 16.65179], [43.21325, 16.74416], [43.25857, 16.75304], [43.26303, 16.79479], [43.24801, 16.80613], [43.22956, 16.80613], [43.22012, 16.83932], [43.18338, 16.84852], [43.1398, 16.90696], [43.19328, 16.94703], [43.1813, 16.98438], [43.18233, 17.02673], [43.23967, 17.03428], [43.17787, 17.14717], [43.20156, 17.25901], [43.32653, 17.31179], [43.22533, 17.38343], [43.29185, 17.53224], [43.43005, 17.56148], [43.70631, 17.35762], [44.50126, 17.47475], [46.31018, 17.20464], [46.76494, 17.29151], [47.00571, 16.94765], [47.48245, 17.10808], [47.58351, 17.50366], [48.19996, 18.20584], [49.04884, 18.59899], [52.00311, 19.00083], [54.99756, 20.00083], [55.66469, 21.99658], [55.2137, 22.71065], [55.13599, 22.63334], [52.56622, 22.94341], [51.59617, 24.12041], [51.58871, 24.27256], [51.41644, 24.39615], [51.58834, 24.66608], [51.39468, 24.62785], [51.29972, 24.50747], [51.09638, 24.46907], [50.92992, 24.54396], [50.8133, 24.74049], [50.57069, 25.57887], [50.302, 25.87592], [50.26923, 26.08243], [50.38162, 26.53976], [50.71771, 26.73086], [50.37726, 27.89227], [49.98877, 27.87827], [49.00421, 28.81495], [48.42991, 28.53628], [47.70561, 28.5221], [47.59863, 28.66798], [47.58376, 28.83382], [47.46202, 29.0014], [46.5527, 29.10283], [46.42415, 29.05947], [44.72255, 29.19736], [42.97796, 30.48295], [42.97601, 30.72204], [40.01521, 32.05667]]]]
26004           }
26005         }, {
26006           type: "Feature",
26007           properties: {
26008             iso1A2: "SB",
26009             iso1A3: "SLB",
26010             iso1N3: "090",
26011             wikidata: "Q685",
26012             nameEn: "Solomon Islands",
26013             groups: ["054", "009", "UN"],
26014             driveSide: "left",
26015             callingCodes: ["677"]
26016           },
26017           geometry: {
26018             type: "MultiPolygon",
26019             coordinates: [[[[172.71443, -12.01327], [160.43769, -4.17974], [156.03296, -6.55528], [156.03993, -6.65703], [155.92557, -6.84664], [155.69784, -6.92661], [155.60735, -6.92266], [154.74815, -7.33315], [156.73836, -14.50464], [172.71443, -12.01327]]]]
26020           }
26021         }, {
26022           type: "Feature",
26023           properties: {
26024             iso1A2: "SC",
26025             iso1A3: "SYC",
26026             iso1N3: "690",
26027             wikidata: "Q1042",
26028             nameEn: "Seychelles",
26029             groups: ["014", "202", "002", "UN"],
26030             driveSide: "left",
26031             callingCodes: ["248"]
26032           },
26033           geometry: {
26034             type: "MultiPolygon",
26035             coordinates: [[[[43.75112, -10.38913], [54.83239, -10.93575], [66.3222, 5.65313], [43.75112, -10.38913]]]]
26036           }
26037         }, {
26038           type: "Feature",
26039           properties: {
26040             iso1A2: "SD",
26041             iso1A3: "SDN",
26042             iso1N3: "729",
26043             wikidata: "Q1049",
26044             nameEn: "Sudan",
26045             groups: ["015", "002", "UN"],
26046             callingCodes: ["249"]
26047           },
26048           geometry: {
26049             type: "MultiPolygon",
26050             coordinates: [[[[37.8565, 22.00903], [34.0765, 22.00501], [33.99686, 21.76784], [33.57251, 21.72406], [33.17563, 22.00405], [24.99885, 21.99535], [24.99794, 19.99661], [23.99715, 20.00038], [23.99539, 19.49944], [23.99997, 15.69575], [23.62785, 15.7804], [23.38812, 15.69649], [23.10792, 15.71297], [22.93201, 15.55107], [22.92579, 15.47007], [22.99584, 15.40105], [22.99584, 15.22989], [22.66115, 14.86308], [22.70474, 14.69149], [22.38562, 14.58907], [22.44944, 14.24986], [22.55997, 14.23024], [22.5553, 14.11704], [22.22995, 13.96754], [22.08674, 13.77863], [22.29689, 13.3731], [22.1599, 13.19281], [22.02914, 13.13976], [21.94819, 13.05637], [21.81432, 12.81362], [21.89371, 12.68001], [21.98711, 12.63292], [22.15679, 12.66634], [22.22684, 12.74682], [22.46345, 12.61925], [22.38873, 12.45514], [22.50548, 12.16769], [22.48369, 12.02766], [22.64092, 12.07485], [22.54907, 11.64372], [22.7997, 11.40424], [22.93124, 11.41645], [22.97249, 11.21955], [22.87758, 10.91915], [23.02221, 10.69235], [23.3128, 10.45214], [23.67164, 9.86923], [23.69155, 9.67566], [24.09319, 9.66572], [24.12744, 9.73784], [24.49389, 9.79962], [24.84653, 9.80643], [24.97739, 9.9081], [25.05688, 10.06776], [25.0918, 10.33718], [25.78141, 10.42599], [25.93163, 10.38159], [25.93241, 10.17941], [26.21338, 9.91545], [26.35815, 9.57946], [26.70685, 9.48735], [27.14427, 9.62858], [27.90704, 9.61323], [28.99983, 9.67155], [29.06988, 9.74826], [29.53844, 9.75133], [29.54, 10.07949], [29.94629, 10.29245], [30.00389, 10.28633], [30.53005, 9.95992], [30.82893, 9.71451], [30.84605, 9.7498], [31.28504, 9.75287], [31.77539, 10.28939], [31.99177, 10.65065], [32.46967, 11.04662], [32.39358, 11.18207], [32.39578, 11.70208], [32.10079, 11.95203], [32.73921, 11.95203], [32.73921, 12.22757], [33.25876, 12.22111], [33.13988, 11.43248], [33.26977, 10.83632], [33.24645, 10.77913], [33.52294, 10.64382], [33.66604, 10.44254], [33.80913, 10.32994], [33.90159, 10.17179], [33.96984, 10.15446], [33.99185, 9.99623], [33.96323, 9.80972], [33.9082, 9.762], [33.87958, 9.49937], [34.10229, 9.50238], [34.08717, 9.55243], [34.13186, 9.7492], [34.20484, 9.9033], [34.22718, 10.02506], [34.32102, 10.11599], [34.34783, 10.23914], [34.2823, 10.53508], [34.4372, 10.781], [34.59062, 10.89072], [34.77383, 10.74588], [34.77532, 10.69027], [34.86618, 10.74588], [34.86916, 10.78832], [34.97491, 10.86147], [34.97789, 10.91559], [34.93172, 10.95946], [35.01215, 11.19626], [34.95704, 11.24448], [35.09556, 11.56278], [35.05832, 11.71158], [35.11492, 11.85156], [35.24302, 11.91132], [35.70476, 12.67101], [36.01458, 12.72478], [36.14268, 12.70879], [36.16651, 12.88019], [36.13374, 12.92665], [36.24545, 13.36759], [36.38993, 13.56459], [36.48824, 13.83954], [36.44653, 13.95666], [36.54376, 14.25597], [36.44337, 15.14963], [36.54276, 15.23478], [36.69761, 15.75323], [36.76371, 15.80831], [36.92193, 16.23451], [36.99777, 17.07172], [37.42694, 17.04041], [37.50967, 17.32199], [38.13362, 17.53906], [38.37133, 17.66269], [38.45916, 17.87167], [38.57727, 17.98125], [39.63762, 18.37348], [37.8565, 22.00903]]]]
26051           }
26052         }, {
26053           type: "Feature",
26054           properties: {
26055             iso1A2: "SE",
26056             iso1A3: "SWE",
26057             iso1N3: "752",
26058             wikidata: "Q34",
26059             nameEn: "Sweden",
26060             groups: ["EU", "154", "150", "UN"],
26061             callingCodes: ["46"]
26062           },
26063           geometry: {
26064             type: "MultiPolygon",
26065             coordinates: [[[[24.15791, 65.85385], [23.90497, 66.15802], [23.71339, 66.21299], [23.64982, 66.30603], [23.67591, 66.3862], [23.63776, 66.43568], [23.85959, 66.56434], [23.89488, 66.772], [23.98059, 66.79585], [23.98563, 66.84149], [23.56214, 67.17038], [23.58735, 67.20752], [23.54701, 67.25435], [23.75372, 67.29914], [23.75372, 67.43688], [23.39577, 67.46974], [23.54701, 67.59306], [23.45627, 67.85297], [23.65793, 67.9497], [23.40081, 68.05545], [23.26469, 68.15134], [23.15377, 68.14759], [23.10336, 68.26551], [22.73028, 68.40881], [22.00429, 68.50692], [21.03001, 68.88969], [20.90649, 68.89696], [20.85104, 68.93142], [20.91658, 68.96764], [20.78802, 69.03087], [20.55258, 69.06069], [20.0695, 69.04469], [20.28444, 68.93283], [20.33435, 68.80174], [20.22027, 68.67246], [19.95647, 68.55546], [20.22027, 68.48759], [19.93508, 68.35911], [18.97255, 68.52416], [18.63032, 68.50849], [18.39503, 68.58672], [18.1241, 68.53721], [18.13836, 68.20874], [17.90787, 67.96537], [17.30416, 68.11591], [16.7409, 67.91037], [16.38441, 67.52923], [16.12774, 67.52106], [16.09922, 67.4364], [16.39154, 67.21653], [16.35589, 67.06419], [15.37197, 66.48217], [15.49318, 66.28509], [15.05113, 66.15572], [14.53778, 66.12399], [14.50926, 65.31786], [13.64276, 64.58402], [14.11117, 64.46674], [14.16051, 64.18725], [13.98222, 64.00953], [13.23411, 64.09087], [12.74105, 64.02171], [12.14928, 63.59373], [12.19919, 63.47935], [11.98529, 63.27487], [12.19919, 63.00104], [12.07085, 62.6297], [12.29187, 62.25699], [12.14746, 61.7147], [12.40595, 61.57226], [12.57707, 61.56547], [12.86939, 61.35427], [12.69115, 61.06584], [12.2277, 61.02442], [12.59133, 60.50559], [12.52003, 60.13846], [12.36317, 59.99259], [12.15641, 59.8926], [11.87121, 59.86039], [11.92112, 59.69531], [11.69297, 59.59442], [11.8213, 59.24985], [11.65732, 58.90177], [11.45199, 58.89604], [11.4601, 58.99022], [11.34459, 59.11672], [11.15367, 59.07862], [11.08911, 58.98745], [10.64958, 58.89391], [10.40861, 58.38489], [12.16597, 56.60205], [12.07466, 56.29488], [12.65312, 56.04345], [12.6372, 55.91371], [12.88472, 55.63369], [12.60345, 55.42675], [12.84405, 55.13257], [14.28399, 55.1553], [14.89259, 55.5623], [15.79951, 55.54655], [19.64795, 57.06466], [19.84909, 57.57876], [20.5104, 59.15546], [19.08191, 60.19152], [19.23413, 60.61414], [20.15877, 63.06556], [24.14112, 65.39731], [24.15107, 65.81427], [24.14798, 65.83466], [24.15791, 65.85385]]]]
26066           }
26067         }, {
26068           type: "Feature",
26069           properties: {
26070             iso1A2: "SG",
26071             iso1A3: "SGP",
26072             iso1N3: "702",
26073             wikidata: "Q334",
26074             nameEn: "Singapore",
26075             groups: ["035", "142", "UN"],
26076             driveSide: "left",
26077             callingCodes: ["65"]
26078           },
26079           geometry: {
26080             type: "MultiPolygon",
26081             coordinates: [[[[104.00131, 1.42405], [103.93384, 1.42926], [103.89565, 1.42841], [103.86383, 1.46288], [103.81181, 1.47953], [103.76395, 1.45183], [103.74161, 1.4502], [103.7219, 1.46108], [103.67468, 1.43166], [103.62738, 1.35255], [103.56591, 1.19719], [103.66049, 1.18825], [103.74084, 1.12902], [104.03085, 1.26954], [104.12282, 1.27714], [104.08072, 1.35998], [104.09162, 1.39694], [104.08871, 1.42015], [104.07348, 1.43322], [104.04622, 1.44691], [104.02277, 1.4438], [104.00131, 1.42405]]]]
26082           }
26083         }, {
26084           type: "Feature",
26085           properties: {
26086             iso1A2: "SH",
26087             iso1A3: "SHN",
26088             iso1N3: "654",
26089             wikidata: "Q192184",
26090             nameEn: "Saint Helena, Ascension and Tristan da Cunha",
26091             country: "GB"
26092           },
26093           geometry: null
26094         }, {
26095           type: "Feature",
26096           properties: {
26097             iso1A2: "SI",
26098             iso1A3: "SVN",
26099             iso1N3: "705",
26100             wikidata: "Q215",
26101             nameEn: "Slovenia",
26102             groups: ["EU", "039", "150", "UN"],
26103             callingCodes: ["386"]
26104           },
26105           geometry: {
26106             type: "MultiPolygon",
26107             coordinates: [[[[16.50139, 46.56684], [16.39217, 46.63673], [16.38594, 46.6549], [16.41863, 46.66238], [16.42641, 46.69228], [16.37816, 46.69975], [16.30966, 46.7787], [16.31303, 46.79838], [16.3408, 46.80641], [16.34547, 46.83836], [16.2941, 46.87137], [16.2365, 46.87775], [16.21892, 46.86961], [16.15711, 46.85434], [16.14365, 46.8547], [16.10983, 46.867], [16.05786, 46.83927], [15.99054, 46.82772], [15.99126, 46.78199], [15.98432, 46.74991], [15.99769, 46.7266], [16.02808, 46.71094], [16.04347, 46.68694], [16.04036, 46.6549], [15.99988, 46.67947], [15.98512, 46.68463], [15.94864, 46.68769], [15.87691, 46.7211], [15.8162, 46.71897], [15.78518, 46.70712], [15.76771, 46.69863], [15.73823, 46.70011], [15.72279, 46.69548], [15.69523, 46.69823], [15.67411, 46.70735], [15.6543, 46.70616], [15.6543, 46.69228], [15.6365, 46.6894], [15.63255, 46.68069], [15.62317, 46.67947], [15.59826, 46.68908], [15.54533, 46.66985], [15.55333, 46.64988], [15.54431, 46.6312], [15.46906, 46.61321], [15.45514, 46.63697], [15.41235, 46.65556], [15.23711, 46.63994], [15.14215, 46.66131], [15.01451, 46.641], [14.98024, 46.6009], [14.96002, 46.63459], [14.92283, 46.60848], [14.87129, 46.61], [14.86419, 46.59411], [14.83549, 46.56614], [14.81836, 46.51046], [14.72185, 46.49974], [14.66892, 46.44936], [14.5942, 46.43434], [14.56463, 46.37208], [14.52176, 46.42617], [14.45877, 46.41717], [14.42608, 46.44614], [14.314, 46.43327], [14.28326, 46.44315], [14.15989, 46.43327], [14.12097, 46.47724], [14.04002, 46.49117], [14.00422, 46.48474], [13.89837, 46.52331], [13.7148, 46.5222], [13.68684, 46.43881], [13.59777, 46.44137], [13.5763, 46.42613], [13.5763, 46.40915], [13.47019, 46.3621], [13.43418, 46.35992], [13.44808, 46.33507], [13.37671, 46.29668], [13.42218, 46.20758], [13.47587, 46.22725], [13.56114, 46.2054], [13.56682, 46.18703], [13.64451, 46.18966], [13.66472, 46.17392], [13.64053, 46.13587], [13.57072, 46.09022], [13.50104, 46.05986], [13.49568, 46.04839], [13.50998, 46.04498], [13.49702, 46.01832], [13.47474, 46.00546], [13.50104, 45.98078], [13.52963, 45.96588], [13.56759, 45.96991], [13.58903, 45.99009], [13.62074, 45.98388], [13.63458, 45.98947], [13.64307, 45.98326], [13.6329, 45.94894], [13.63815, 45.93607], [13.61931, 45.91782], [13.60857, 45.89907], [13.59565, 45.89446], [13.58644, 45.88173], [13.57563, 45.8425], [13.58858, 45.83503], [13.59784, 45.8072], [13.66986, 45.79955], [13.8235, 45.7176], [13.83332, 45.70855], [13.83422, 45.68703], [13.87933, 45.65207], [13.9191, 45.6322], [13.8695, 45.60835], [13.86771, 45.59898], [13.84106, 45.58185], [13.78445, 45.5825], [13.74587, 45.59811], [13.7198, 45.59352], [13.6076, 45.64761], [13.45644, 45.59464], [13.56979, 45.4895], [13.62902, 45.45898], [13.67398, 45.4436], [13.7785, 45.46787], [13.81742, 45.43729], [13.88124, 45.42637], [13.90771, 45.45149], [13.97309, 45.45258], [13.99488, 45.47551], [13.96063, 45.50825], [14.00578, 45.52352], [14.07116, 45.48752], [14.20348, 45.46896], [14.22371, 45.50388], [14.24239, 45.50607], [14.26611, 45.48239], [14.27681, 45.4902], [14.32487, 45.47142], [14.36693, 45.48642], [14.49769, 45.54424], [14.5008, 45.60852], [14.53816, 45.6205], [14.57397, 45.67165], [14.60977, 45.66403], [14.59576, 45.62812], [14.69694, 45.57366], [14.68605, 45.53006], [14.71718, 45.53442], [14.80124, 45.49515], [14.81992, 45.45913], [14.90554, 45.47769], [14.92266, 45.52788], [15.02385, 45.48533], [15.05187, 45.49079], [15.16862, 45.42309], [15.27758, 45.46678], [15.33051, 45.45258], [15.38188, 45.48752], [15.30249, 45.53224], [15.29837, 45.5841], [15.27747, 45.60504], [15.31027, 45.6303], [15.34695, 45.63382], [15.34214, 45.64702], [15.38952, 45.63682], [15.4057, 45.64727], [15.34919, 45.71623], [15.30872, 45.69014], [15.25423, 45.72275], [15.40836, 45.79491], [15.47531, 45.79802], [15.47325, 45.8253], [15.52234, 45.82195], [15.57952, 45.84953], [15.64185, 45.82915], [15.66662, 45.84085], [15.70411, 45.8465], [15.68232, 45.86819], [15.68383, 45.88867], [15.67967, 45.90455], [15.70636, 45.92116], [15.70327, 46.00015], [15.71246, 46.01196], [15.72977, 46.04682], [15.62317, 46.09103], [15.6083, 46.11992], [15.59909, 46.14761], [15.64904, 46.19229], [15.6434, 46.21396], [15.67395, 46.22478], [15.75436, 46.21969], [15.75479, 46.20336], [15.78817, 46.21719], [15.79284, 46.25811], [15.97965, 46.30652], [16.07616, 46.3463], [16.07314, 46.36458], [16.05065, 46.3833], [16.05281, 46.39141], [16.14859, 46.40547], [16.18824, 46.38282], [16.30233, 46.37837], [16.30162, 46.40437], [16.27329, 46.41467], [16.27398, 46.42875], [16.25124, 46.48067], [16.23961, 46.49653], [16.26759, 46.50566], [16.26733, 46.51505], [16.29793, 46.5121], [16.37193, 46.55008], [16.38771, 46.53608], [16.44036, 46.5171], [16.5007, 46.49644], [16.52604, 46.47831], [16.59527, 46.47524], [16.52604, 46.5051], [16.52885, 46.53303], [16.50139, 46.56684]]]]
26108           }
26109         }, {
26110           type: "Feature",
26111           properties: {
26112             iso1A2: "SJ",
26113             iso1A3: "SJM",
26114             iso1N3: "744",
26115             wikidata: "Q842829",
26116             nameEn: "Svalbard and Jan Mayen",
26117             country: "NO"
26118           },
26119           geometry: null
26120         }, {
26121           type: "Feature",
26122           properties: {
26123             iso1A2: "SK",
26124             iso1A3: "SVK",
26125             iso1N3: "703",
26126             wikidata: "Q214",
26127             nameEn: "Slovakia",
26128             groups: ["EU", "151", "150", "UN"],
26129             callingCodes: ["421"]
26130           },
26131           geometry: {
26132             type: "MultiPolygon",
26133             coordinates: [[[[19.82237, 49.27806], [19.78581, 49.41701], [19.72127, 49.39288], [19.6375, 49.40897], [19.64162, 49.45184], [19.57845, 49.46077], [19.53313, 49.52856], [19.52626, 49.57311], [19.45348, 49.61583], [19.37795, 49.574], [19.36009, 49.53747], [19.25435, 49.53391], [19.18019, 49.41165], [18.9742, 49.39557], [18.97283, 49.49914], [18.94536, 49.52143], [18.84521, 49.51672], [18.74761, 49.492], [18.67757, 49.50895], [18.6144, 49.49824], [18.57183, 49.51162], [18.53063, 49.49022], [18.54848, 49.47059], [18.44686, 49.39467], [18.4084, 49.40003], [18.4139, 49.36517], [18.36446, 49.3267], [18.18456, 49.28909], [18.15022, 49.24518], [18.1104, 49.08624], [18.06885, 49.03157], [17.91814, 49.01784], [17.87831, 48.92679], [17.77944, 48.92318], [17.73126, 48.87885], [17.7094, 48.86721], [17.5295, 48.81117], [17.45671, 48.85004], [17.3853, 48.80936], [17.29054, 48.85546], [17.19355, 48.87602], [17.11202, 48.82925], [17.00215, 48.70887], [16.93955, 48.60371], [16.94611, 48.53614], [16.85204, 48.44968], [16.8497, 48.38321], [16.83588, 48.3844], [16.83317, 48.38138], [16.84243, 48.35258], [16.90903, 48.32519], [16.89461, 48.31332], [16.97701, 48.17385], [17.02919, 48.13996], [17.05735, 48.14179], [17.09168, 48.09366], [17.07039, 48.0317], [17.16001, 48.00636], [17.23699, 48.02094], [17.71215, 47.7548], [18.02938, 47.75665], [18.29305, 47.73541], [18.56496, 47.76588], [18.66521, 47.76772], [18.74074, 47.8157], [18.8506, 47.82308], [18.76821, 47.87469], [18.76134, 47.97499], [18.82176, 48.04206], [19.01952, 48.07052], [19.23924, 48.0595], [19.28182, 48.08336], [19.47957, 48.09437], [19.52489, 48.19791], [19.63338, 48.25006], [19.92452, 48.1283], [20.24312, 48.2784], [20.29943, 48.26104], [20.5215, 48.53336], [20.83248, 48.5824], [21.11516, 48.49546], [21.44063, 48.58456], [21.6068, 48.50365], [21.67134, 48.3989], [21.72525, 48.34628], [21.8279, 48.33321], [21.83339, 48.36242], [22.14689, 48.4005], [22.16023, 48.56548], [22.21379, 48.6218], [22.34151, 48.68893], [22.42934, 48.92857], [22.48296, 48.99172], [22.54338, 49.01424], [22.56155, 49.08865], [22.04427, 49.22136], [21.96385, 49.3437], [21.82927, 49.39467], [21.77983, 49.35443], [21.62328, 49.4447], [21.43376, 49.41433], [21.27858, 49.45988], [21.19756, 49.4054], [21.12477, 49.43666], [21.041, 49.41791], [21.09799, 49.37176], [20.98733, 49.30774], [20.9229, 49.29626], [20.77971, 49.35383], [20.72274, 49.41813], [20.61666, 49.41791], [20.5631, 49.375], [20.46422, 49.41612], [20.39939, 49.3896], [20.31728, 49.39914], [20.31453, 49.34817], [20.21977, 49.35265], [20.13738, 49.31685], [20.08238, 49.1813], [19.98494, 49.22904], [19.90529, 49.23532], [19.86409, 49.19316], [19.75286, 49.20751], [19.82237, 49.27806]]]]
26134           }
26135         }, {
26136           type: "Feature",
26137           properties: {
26138             iso1A2: "SL",
26139             iso1A3: "SLE",
26140             iso1N3: "694",
26141             wikidata: "Q1044",
26142             nameEn: "Sierra Leone",
26143             groups: ["011", "202", "002", "UN"],
26144             callingCodes: ["232"]
26145           },
26146           geometry: {
26147             type: "MultiPolygon",
26148             coordinates: [[[[-10.27575, 8.48711], [-10.37257, 8.48941], [-10.54891, 8.31174], [-10.63934, 8.35326], [-10.70565, 8.29235], [-10.61422, 8.5314], [-10.47707, 8.67669], [-10.56197, 8.81225], [-10.5783, 9.06386], [-10.74484, 9.07998], [-10.6534, 9.29919], [-11.2118, 10.00098], [-11.89624, 9.99763], [-11.91023, 9.93927], [-12.12634, 9.87203], [-12.24262, 9.92386], [-12.47254, 9.86834], [-12.76788, 9.3133], [-12.94095, 9.26335], [-13.08953, 9.0409], [-13.18586, 9.0925], [-13.29911, 9.04245], [-14.36218, 8.64107], [-12.15048, 6.15992], [-11.50429, 6.92704], [-11.4027, 6.97746], [-11.29417, 7.21576], [-10.60422, 7.7739], [-10.60492, 8.04072], [-10.57523, 8.04829], [-10.51554, 8.1393], [-10.45023, 8.15627], [-10.35227, 8.15223], [-10.29839, 8.21283], [-10.31635, 8.28554], [-10.30084, 8.30008], [-10.27575, 8.48711]]]]
26149           }
26150         }, {
26151           type: "Feature",
26152           properties: {
26153             iso1A2: "SM",
26154             iso1A3: "SMR",
26155             iso1N3: "674",
26156             wikidata: "Q238",
26157             nameEn: "San Marino",
26158             groups: ["039", "150", "UN"],
26159             callingCodes: ["378"]
26160           },
26161           geometry: {
26162             type: "MultiPolygon",
26163             coordinates: [[[[12.45648, 43.89369], [12.48771, 43.89706], [12.49429, 43.90973], [12.49247, 43.91774], [12.49724, 43.92248], [12.50269, 43.92363], [12.50496, 43.93017], [12.51553, 43.94096], [12.51427, 43.94897], [12.50655, 43.95796], [12.50875, 43.96198], [12.50622, 43.97131], [12.51109, 43.97201], [12.51064, 43.98165], [12.5154, 43.98508], [12.51463, 43.99122], [12.50678, 43.99113], [12.49406, 43.98492], [12.47853, 43.98052], [12.46205, 43.97463], [12.44684, 43.96597], [12.43662, 43.95698], [12.42005, 43.9578], [12.41414, 43.95273], [12.40415, 43.95485], [12.40506, 43.94325], [12.41165, 43.93769], [12.41551, 43.92984], [12.40733, 43.92379], [12.41233, 43.90956], [12.40935, 43.9024], [12.41641, 43.89991], [12.44184, 43.90498], [12.45648, 43.89369]]]]
26164           }
26165         }, {
26166           type: "Feature",
26167           properties: {
26168             iso1A2: "SN",
26169             iso1A3: "SEN",
26170             iso1N3: "686",
26171             wikidata: "Q1041",
26172             nameEn: "Senegal",
26173             groups: ["011", "202", "002", "UN"],
26174             callingCodes: ["221"]
26175           },
26176           geometry: {
26177             type: "MultiPolygon",
26178             coordinates: [[[[-14.32144, 16.61495], [-15.00557, 16.64997], [-15.6509, 16.50315], [-16.27016, 16.51565], [-16.4429, 16.20605], [-16.44814, 16.09753], [-16.48967, 16.0496], [-16.50854, 16.09032], [-17.15288, 16.07139], [-18.35085, 14.63444], [-17.43598, 13.59273], [-15.47902, 13.58758], [-15.36504, 13.79313], [-14.93719, 13.80173], [-14.34721, 13.46578], [-13.8955, 13.59126], [-13.79409, 13.34472], [-14.36795, 13.23033], [-15.14917, 13.57989], [-15.26908, 13.37768], [-15.80478, 13.34832], [-15.80355, 13.16729], [-16.69343, 13.16791], [-16.74676, 13.06025], [-17.43966, 13.04579], [-17.4623, 11.92379], [-16.70562, 12.34803], [-16.38191, 12.36449], [-16.20591, 12.46157], [-15.67302, 12.42974], [-15.17582, 12.6847], [-13.70523, 12.68013], [-13.05296, 12.64003], [-13.06603, 12.49342], [-12.87336, 12.51892], [-12.35415, 12.32758], [-11.91331, 12.42008], [-11.46267, 12.44559], [-11.37536, 12.40788], [-11.39935, 12.97808], [-11.63025, 13.39174], [-11.83345, 13.33333], [-12.06897, 13.71049], [-11.93043, 13.84505], [-12.23936, 14.76324], [-13.11029, 15.52116], [-13.43135, 16.09022], [-13.80075, 16.13961], [-14.32144, 16.61495]]]]
26179           }
26180         }, {
26181           type: "Feature",
26182           properties: {
26183             iso1A2: "SO",
26184             iso1A3: "SOM",
26185             iso1N3: "706",
26186             wikidata: "Q1045",
26187             nameEn: "Somalia",
26188             groups: ["014", "202", "002", "UN"],
26189             callingCodes: ["252"]
26190           },
26191           geometry: {
26192             type: "MultiPolygon",
26193             coordinates: [[[[51.12877, 12.56479], [43.90659, 12.3823], [42.95776, 10.98533], [42.69452, 10.62672], [42.87643, 10.18441], [43.0937, 9.90579], [43.23518, 9.84605], [43.32613, 9.59205], [44.19222, 8.93028], [46.99339, 7.9989], [47.92477, 8.00111], [47.97917, 8.00124], [44.98104, 4.91821], [44.02436, 4.9451], [43.40263, 4.79289], [43.04177, 4.57923], [42.97746, 4.44032], [42.84526, 4.28357], [42.55853, 4.20518], [42.07619, 4.17667], [41.89488, 3.97375], [41.31368, 3.14314], [40.98767, 2.82959], [41.00099, -0.83068], [41.56, -1.59812], [41.56362, -1.66375], [41.75542, -1.85308], [57.49095, 8.14549], [51.12877, 12.56479]]]]
26194           }
26195         }, {
26196           type: "Feature",
26197           properties: {
26198             iso1A2: "SR",
26199             iso1A3: "SUR",
26200             iso1N3: "740",
26201             wikidata: "Q730",
26202             nameEn: "Suriname",
26203             groups: ["005", "419", "019", "UN"],
26204             driveSide: "left",
26205             callingCodes: ["597"]
26206           },
26207           geometry: {
26208             type: "MultiPolygon",
26209             coordinates: [[[[-54.26916, 5.26909], [-54.01877, 5.52789], [-54.01074, 5.68785], [-53.7094, 6.2264], [-56.84822, 6.73257], [-57.31629, 5.33714], [-57.22536, 5.15605], [-57.37442, 5.0208], [-57.8699, 4.89394], [-58.0307, 3.95513], [-57.35891, 3.32121], [-56.70519, 2.02964], [-56.55439, 2.02003], [-56.47045, 1.95135], [-55.99278, 1.83137], [-55.89863, 1.89861], [-55.92159, 2.05236], [-56.13054, 2.27723], [-55.96292, 2.53188], [-55.71493, 2.40342], [-55.01919, 2.564], [-54.6084, 2.32856], [-54.42864, 2.42442], [-54.28534, 2.67798], [-53.9849, 3.58697], [-53.98914, 3.627], [-54.05128, 3.63557], [-54.19367, 3.84387], [-54.38444, 4.13222], [-54.4717, 4.91964], [-54.26916, 5.26909]]]]
26210           }
26211         }, {
26212           type: "Feature",
26213           properties: {
26214             iso1A2: "SS",
26215             iso1A3: "SSD",
26216             iso1N3: "728",
26217             wikidata: "Q958",
26218             nameEn: "South Sudan",
26219             groups: ["014", "202", "002", "UN"],
26220             callingCodes: ["211"]
26221           },
26222           geometry: {
26223             type: "MultiPolygon",
26224             coordinates: [[[[34.10229, 9.50238], [33.87958, 9.49937], [33.9082, 9.762], [33.96323, 9.80972], [33.99185, 9.99623], [33.96984, 10.15446], [33.90159, 10.17179], [33.80913, 10.32994], [33.66604, 10.44254], [33.52294, 10.64382], [33.24645, 10.77913], [33.26977, 10.83632], [33.13988, 11.43248], [33.25876, 12.22111], [32.73921, 12.22757], [32.73921, 11.95203], [32.10079, 11.95203], [32.39578, 11.70208], [32.39358, 11.18207], [32.46967, 11.04662], [31.99177, 10.65065], [31.77539, 10.28939], [31.28504, 9.75287], [30.84605, 9.7498], [30.82893, 9.71451], [30.53005, 9.95992], [30.00389, 10.28633], [29.94629, 10.29245], [29.54, 10.07949], [29.53844, 9.75133], [29.06988, 9.74826], [28.99983, 9.67155], [27.90704, 9.61323], [27.14427, 9.62858], [26.70685, 9.48735], [26.35815, 9.57946], [26.21338, 9.91545], [25.93241, 10.17941], [25.93163, 10.38159], [25.78141, 10.42599], [25.0918, 10.33718], [25.05688, 10.06776], [24.97739, 9.9081], [24.84653, 9.80643], [24.49389, 9.79962], [24.12744, 9.73784], [24.09319, 9.66572], [23.69155, 9.67566], [23.62179, 9.53823], [23.64981, 9.44303], [23.64358, 9.28637], [23.56263, 9.19418], [23.4848, 9.16959], [23.44744, 8.99128], [23.59065, 8.99743], [23.51905, 8.71749], [24.25691, 8.69288], [24.13238, 8.36959], [24.35965, 8.26177], [24.85156, 8.16933], [24.98855, 7.96588], [25.25319, 7.8487], [25.29214, 7.66675], [25.20649, 7.61115], [25.20337, 7.50312], [25.35281, 7.42595], [25.37461, 7.33024], [25.90076, 7.09549], [26.38022, 6.63493], [26.32729, 6.36272], [26.58259, 6.1987], [26.51721, 6.09655], [27.22705, 5.71254], [27.22705, 5.62889], [27.28621, 5.56382], [27.23017, 5.37167], [27.26886, 5.25876], [27.44012, 5.07349], [27.56656, 4.89375], [27.65462, 4.89375], [27.76469, 4.79284], [27.79551, 4.59976], [28.20719, 4.35614], [28.6651, 4.42638], [28.8126, 4.48784], [29.03054, 4.48784], [29.22207, 4.34297], [29.43341, 4.50101], [29.49726, 4.7007], [29.82087, 4.56246], [29.79666, 4.37809], [30.06964, 4.13221], [30.1621, 4.10586], [30.22374, 3.93896], [30.27658, 3.95653], [30.47691, 3.83353], [30.55396, 3.84451], [30.57378, 3.74567], [30.56277, 3.62703], [30.78512, 3.67097], [30.80713, 3.60506], [30.85997, 3.5743], [30.85153, 3.48867], [30.97601, 3.693], [31.16666, 3.79853], [31.29476, 3.8015], [31.50478, 3.67814], [31.50776, 3.63652], [31.72075, 3.74354], [31.81459, 3.82083], [31.86821, 3.78664], [31.96205, 3.6499], [31.95907, 3.57408], [32.05187, 3.589], [32.08491, 3.56287], [32.08866, 3.53543], [32.19888, 3.50867], [32.20782, 3.6053], [32.41337, 3.748], [32.72021, 3.77327], [32.89746, 3.81339], [33.02852, 3.89296], [33.18356, 3.77812], [33.51264, 3.75068], [33.9873, 4.23316], [34.47601, 4.72162], [35.34151, 5.02364], [35.30992, 4.90402], [35.47843, 4.91872], [35.42366, 4.76969], [35.51424, 4.61643], [35.9419, 4.61933], [35.82118, 4.77382], [35.81968, 5.10757], [35.8576, 5.33413], [35.50792, 5.42431], [35.29938, 5.34042], [35.31188, 5.50106], [35.13058, 5.62118], [35.12611, 5.68937], [35.00546, 5.89387], [34.96227, 6.26415], [35.01738, 6.46991], [34.87736, 6.60161], [34.77459, 6.5957], [34.65096, 6.72589], [34.53776, 6.74808], [34.53925, 6.82794], [34.47669, 6.91076], [34.35753, 6.91963], [34.19369, 7.04382], [34.19369, 7.12807], [34.01495, 7.25664], [34.03878, 7.27437], [34.02984, 7.36449], [33.87642, 7.5491], [33.71407, 7.65983], [33.44745, 7.7543], [33.32531, 7.71297], [33.24637, 7.77939], [33.04944, 7.78989], [33.0006, 7.90333], [33.08401, 8.05822], [33.18083, 8.13047], [33.1853, 8.29264], [33.19721, 8.40317], [33.3119, 8.45474], [33.54575, 8.47094], [33.66938, 8.44442], [33.71407, 8.3678], [33.87195, 8.41938], [33.89579, 8.4842], [34.01346, 8.50041], [34.14453, 8.60204], [34.14304, 9.04654], [34.10229, 9.50238]]]]
26225           }
26226         }, {
26227           type: "Feature",
26228           properties: {
26229             iso1A2: "ST",
26230             iso1A3: "STP",
26231             iso1N3: "678",
26232             wikidata: "Q1039",
26233             nameEn: "S\xE3o Tom\xE9 and Principe",
26234             groups: ["017", "202", "002", "UN"],
26235             callingCodes: ["239"]
26236           },
26237           geometry: {
26238             type: "MultiPolygon",
26239             coordinates: [[[[4.34149, 1.91417], [6.6507, -0.28606], [7.9035, 1.92304], [4.34149, 1.91417]]]]
26240           }
26241         }, {
26242           type: "Feature",
26243           properties: {
26244             iso1A2: "SV",
26245             iso1A3: "SLV",
26246             iso1N3: "222",
26247             wikidata: "Q792",
26248             nameEn: "El Salvador",
26249             groups: ["013", "003", "419", "019", "UN"],
26250             callingCodes: ["503"]
26251           },
26252           geometry: {
26253             type: "MultiPolygon",
26254             coordinates: [[[[-89.34776, 14.43013], [-89.39028, 14.44561], [-89.57441, 14.41637], [-89.58814, 14.33165], [-89.50614, 14.26084], [-89.52397, 14.22628], [-89.61844, 14.21937], [-89.70756, 14.1537], [-89.75569, 14.07073], [-89.73251, 14.04133], [-89.76103, 14.02923], [-89.81807, 14.07073], [-89.88937, 14.0396], [-90.10505, 13.85104], [-90.11344, 13.73679], [-90.55276, 12.8866], [-88.11443, 12.63306], [-87.7346, 13.13228], [-87.55124, 13.12523], [-87.69751, 13.25228], [-87.73714, 13.32715], [-87.80177, 13.35689], [-87.84675, 13.41078], [-87.83467, 13.44655], [-87.77354, 13.45767], [-87.73841, 13.44169], [-87.72115, 13.46083], [-87.71657, 13.50577], [-87.78148, 13.52906], [-87.73106, 13.75443], [-87.68821, 13.80829], [-87.7966, 13.91353], [-88.00331, 13.86948], [-88.07641, 13.98447], [-88.23018, 13.99915], [-88.25791, 13.91108], [-88.48982, 13.86458], [-88.49738, 13.97224], [-88.70661, 14.04317], [-88.73182, 14.10919], [-88.815, 14.11652], [-88.85785, 14.17763], [-88.94608, 14.20207], [-89.04187, 14.33644], [-89.34776, 14.43013]]]]
26255           }
26256         }, {
26257           type: "Feature",
26258           properties: {
26259             iso1A2: "SX",
26260             iso1A3: "SXM",
26261             iso1N3: "534",
26262             wikidata: "Q26273",
26263             nameEn: "Sint Maarten",
26264             aliases: ["NL-SX"],
26265             country: "NL",
26266             groups: ["Q1451600", "029", "003", "419", "019", "UN"],
26267             callingCodes: ["1 721"]
26268           },
26269           geometry: {
26270             type: "MultiPolygon",
26271             coordinates: [[[[-63.33064, 17.9615], [-63.1055, 17.86651], [-62.93924, 18.02904], [-63.02323, 18.05757], [-63.04039, 18.05619], [-63.0579, 18.06614], [-63.07759, 18.04943], [-63.09686, 18.04608], [-63.11042, 18.05339], [-63.13502, 18.05445], [-63.33064, 17.9615]]]]
26272           }
26273         }, {
26274           type: "Feature",
26275           properties: {
26276             iso1A2: "SY",
26277             iso1A3: "SYR",
26278             iso1N3: "760",
26279             wikidata: "Q858",
26280             nameEn: "Syria",
26281             groups: ["145", "142", "UN"],
26282             callingCodes: ["963"]
26283           },
26284           geometry: {
26285             type: "MultiPolygon",
26286             coordinates: [[[[42.23683, 37.2863], [42.21548, 37.28026], [42.20454, 37.28715], [42.22381, 37.30238], [42.22257, 37.31395], [42.2112, 37.32491], [42.19301, 37.31323], [42.18225, 37.28569], [42.00894, 37.17209], [41.515, 37.08084], [41.21937, 37.07665], [40.90856, 37.13147], [40.69136, 37.0996], [39.81589, 36.75538], [39.21538, 36.66834], [39.03217, 36.70911], [38.74042, 36.70629], [38.55908, 36.84429], [38.38859, 36.90064], [38.21064, 36.91842], [37.81974, 36.76055], [37.68048, 36.75065], [37.49103, 36.66904], [37.47253, 36.63243], [37.21988, 36.6736], [37.16177, 36.66069], [37.10894, 36.6704], [37.08279, 36.63495], [37.02088, 36.66422], [37.01647, 36.69512], [37.04619, 36.71101], [37.04399, 36.73483], [36.99886, 36.74012], [36.99557, 36.75997], [36.66727, 36.82901], [36.61581, 36.74629], [36.62681, 36.71189], [36.57398, 36.65186], [36.58829, 36.58295], [36.54206, 36.49539], [36.6081, 36.33772], [36.65653, 36.33861], [36.68672, 36.23677], [36.6125, 36.22592], [36.50463, 36.2419], [36.4617, 36.20461], [36.39206, 36.22088], [36.37474, 36.01163], [36.33956, 35.98687], [36.30099, 36.00985], [36.28338, 36.00273], [36.29769, 35.96086], [36.27678, 35.94839], [36.25366, 35.96264], [36.19973, 35.95195], [36.17441, 35.92076], [36.1623, 35.80925], [36.14029, 35.81015], [36.13919, 35.83692], [36.11827, 35.85923], [35.99829, 35.88242], [36.01844, 35.92403], [36.00514, 35.94113], [35.98499, 35.94107], [35.931, 35.92109], [35.51152, 36.10954], [35.48515, 34.70851], [35.97386, 34.63322], [35.98718, 34.64977], [36.29165, 34.62991], [36.32399, 34.69334], [36.35135, 34.68516], [36.35384, 34.65447], [36.42941, 34.62505], [36.46003, 34.6378], [36.45299, 34.59438], [36.41429, 34.61175], [36.39846, 34.55672], [36.3369, 34.52629], [36.34745, 34.5002], [36.4442, 34.50165], [36.46179, 34.46541], [36.55853, 34.41609], [36.53039, 34.3798], [36.56556, 34.31881], [36.60778, 34.31009], [36.58667, 34.27667], [36.59195, 34.2316], [36.62537, 34.20251], [36.5128, 34.09916], [36.50576, 34.05982], [36.41078, 34.05253], [36.28589, 33.91981], [36.38263, 33.86579], [36.3967, 33.83365], [36.14517, 33.85118], [36.06778, 33.82927], [35.9341, 33.6596], [36.05723, 33.57904], [35.94465, 33.52774], [35.94816, 33.47886], [35.88668, 33.43183], [35.82577, 33.40479], [35.81324, 33.36354], [35.77477, 33.33609], [35.813, 33.3172], [35.77513, 33.27342], [35.81295, 33.24841], [35.81647, 33.2028], [35.83846, 33.19397], [35.84285, 33.16673], [35.81911, 33.1336], [35.81911, 33.11077], [35.84802, 33.1031], [35.87188, 32.98028], [35.89298, 32.9456], [35.87012, 32.91976], [35.84021, 32.8725], [35.83758, 32.82817], [35.78745, 32.77938], [35.75983, 32.74803], [35.88405, 32.71321], [35.93307, 32.71966], [35.96633, 32.66237], [36.02239, 32.65911], [36.08074, 32.51463], [36.20379, 32.52751], [36.20875, 32.49529], [36.23948, 32.50108], [36.40959, 32.37908], [36.83946, 32.31293], [38.79171, 33.37328], [40.64314, 34.31604], [40.97676, 34.39788], [41.12388, 34.65742], [41.2345, 34.80049], [41.21654, 35.1508], [41.26569, 35.42708], [41.38184, 35.62502], [41.37027, 35.84095], [41.2564, 36.06012], [41.28864, 36.35368], [41.40058, 36.52502], [41.81736, 36.58782], [42.36697, 37.0627], [42.35724, 37.10998], [42.32313, 37.17814], [42.34735, 37.22548], [42.2824, 37.2798], [42.26039, 37.27017], [42.23683, 37.2863]]]]
26287           }
26288         }, {
26289           type: "Feature",
26290           properties: {
26291             iso1A2: "SZ",
26292             iso1A3: "SWZ",
26293             iso1N3: "748",
26294             wikidata: "Q1050",
26295             nameEn: "Eswatini",
26296             aliases: ["Swaziland"],
26297             groups: ["018", "202", "002", "UN"],
26298             driveSide: "left",
26299             callingCodes: ["268"]
26300           },
26301           geometry: {
26302             type: "MultiPolygon",
26303             coordinates: [[[[31.86881, -25.99973], [31.4175, -25.71886], [31.31237, -25.7431], [31.13073, -25.91558], [30.95819, -26.26303], [30.78927, -26.48271], [30.81101, -26.84722], [30.88826, -26.79622], [30.97757, -26.92706], [30.96088, -27.0245], [31.15027, -27.20151], [31.49834, -27.31549], [31.97592, -27.31675], [31.97463, -27.11057], [32.00893, -26.8096], [32.09664, -26.80721], [32.13315, -26.84345], [32.13409, -26.5317], [32.07352, -26.40185], [32.10435, -26.15656], [32.08599, -26.00978], [32.00916, -25.999], [31.974, -25.95387], [31.86881, -25.99973]]]]
26304           }
26305         }, {
26306           type: "Feature",
26307           properties: {
26308             iso1A2: "TA",
26309             iso1A3: "TAA",
26310             wikidata: "Q220982",
26311             nameEn: "Tristan da Cunha",
26312             aliases: ["SH-TA"],
26313             country: "GB",
26314             groups: ["SH", "BOTS", "011", "202", "002", "UN"],
26315             isoStatus: "excRes",
26316             driveSide: "left",
26317             roadSpeedUnit: "mph",
26318             roadHeightUnit: "ft",
26319             callingCodes: ["290 8", "44 20"]
26320           },
26321           geometry: {
26322             type: "MultiPolygon",
26323             coordinates: [[[[-13.38232, -34.07258], [-16.67337, -41.9188], [-5.88482, -41.4829], [-13.38232, -34.07258]]]]
26324           }
26325         }, {
26326           type: "Feature",
26327           properties: {
26328             iso1A2: "TC",
26329             iso1A3: "TCA",
26330             iso1N3: "796",
26331             wikidata: "Q18221",
26332             nameEn: "Turks and Caicos Islands",
26333             country: "GB",
26334             groups: ["BOTS", "029", "003", "419", "019", "UN"],
26335             driveSide: "left",
26336             roadSpeedUnit: "mph",
26337             roadHeightUnit: "ft",
26338             callingCodes: ["1 649"]
26339           },
26340           geometry: {
26341             type: "MultiPolygon",
26342             coordinates: [[[[-71.70065, 25.7637], [-72.98446, 20.4801], [-69.80718, 21.35956], [-71.70065, 25.7637]]]]
26343           }
26344         }, {
26345           type: "Feature",
26346           properties: {
26347             iso1A2: "TD",
26348             iso1A3: "TCD",
26349             iso1N3: "148",
26350             wikidata: "Q657",
26351             nameEn: "Chad",
26352             groups: ["017", "202", "002", "UN"],
26353             callingCodes: ["235"]
26354           },
26355           geometry: {
26356             type: "MultiPolygon",
26357             coordinates: [[[[23.99539, 19.49944], [15.99566, 23.49639], [14.99751, 23.00539], [15.19692, 21.99339], [15.20213, 21.49365], [15.28332, 21.44557], [15.62515, 20.95395], [15.57248, 20.92138], [15.55382, 20.86507], [15.56004, 20.79488], [15.59841, 20.74039], [15.6721, 20.70069], [15.99632, 20.35364], [15.75098, 19.93002], [15.6032, 18.77402], [15.50373, 16.89649], [14.37425, 15.72591], [13.86301, 15.04043], [13.78991, 14.87519], [13.809, 14.72915], [13.67878, 14.64013], [13.68573, 14.55276], [13.48259, 14.46704], [13.47559, 14.40881], [13.6302, 13.71094], [14.08251, 13.0797], [14.46881, 13.08259], [14.56101, 12.91036], [14.55058, 12.78256], [14.83314, 12.62963], [14.90827, 12.3269], [14.89019, 12.16593], [14.96952, 12.0925], [15.00146, 12.1223], [15.0349, 12.10698], [15.05786, 12.0608], [15.04808, 11.8731], [15.11579, 11.79313], [15.06595, 11.71126], [15.13149, 11.5537], [15.0585, 11.40481], [15.10021, 11.04101], [15.04957, 11.02347], [15.09127, 10.87431], [15.06737, 10.80921], [15.15532, 10.62846], [15.14936, 10.53915], [15.23724, 10.47764], [15.30874, 10.31063], [15.50535, 10.1098], [15.68761, 9.99344], [15.41408, 9.92876], [15.24618, 9.99246], [15.14043, 9.99246], [15.05999, 9.94845], [14.95722, 9.97926], [14.80082, 9.93818], [14.4673, 10.00264], [14.20411, 10.00055], [14.1317, 9.82413], [14.01793, 9.73169], [13.97544, 9.6365], [14.37094, 9.2954], [14.35707, 9.19611], [14.83566, 8.80557], [15.09484, 8.65982], [15.20426, 8.50892], [15.50743, 7.79302], [15.59272, 7.7696], [15.56964, 7.58936], [15.49743, 7.52179], [15.73118, 7.52006], [15.79942, 7.44149], [16.40703, 7.68809], [16.41583, 7.77971], [16.58315, 7.88657], [16.59415, 7.76444], [16.658, 7.75353], [16.6668, 7.67281], [16.8143, 7.53971], [17.67288, 7.98905], [17.93926, 7.95853], [18.02731, 8.01085], [18.6085, 8.05009], [18.64153, 8.08714], [18.62612, 8.14163], [18.67455, 8.22226], [18.79783, 8.25929], [19.11044, 8.68172], [18.86388, 8.87971], [19.06421, 9.00367], [20.36748, 9.11019], [20.82979, 9.44696], [21.26348, 9.97642], [21.34934, 9.95907], [21.52766, 10.2105], [21.63553, 10.217], [21.71479, 10.29932], [21.72139, 10.64136], [22.45889, 11.00246], [22.87758, 10.91915], [22.97249, 11.21955], [22.93124, 11.41645], [22.7997, 11.40424], [22.54907, 11.64372], [22.64092, 12.07485], [22.48369, 12.02766], [22.50548, 12.16769], [22.38873, 12.45514], [22.46345, 12.61925], [22.22684, 12.74682], [22.15679, 12.66634], [21.98711, 12.63292], [21.89371, 12.68001], [21.81432, 12.81362], [21.94819, 13.05637], [22.02914, 13.13976], [22.1599, 13.19281], [22.29689, 13.3731], [22.08674, 13.77863], [22.22995, 13.96754], [22.5553, 14.11704], [22.55997, 14.23024], [22.44944, 14.24986], [22.38562, 14.58907], [22.70474, 14.69149], [22.66115, 14.86308], [22.99584, 15.22989], [22.99584, 15.40105], [22.92579, 15.47007], [22.93201, 15.55107], [23.10792, 15.71297], [23.38812, 15.69649], [23.62785, 15.7804], [23.99997, 15.69575], [23.99539, 19.49944]]]]
26358           }
26359         }, {
26360           type: "Feature",
26361           properties: {
26362             iso1A2: "TF",
26363             iso1A3: "ATF",
26364             iso1N3: "260",
26365             wikidata: "Q129003",
26366             nameEn: "French Southern Territories",
26367             country: "FR"
26368           },
26369           geometry: null
26370         }, {
26371           type: "Feature",
26372           properties: {
26373             iso1A2: "TG",
26374             iso1A3: "TGO",
26375             iso1N3: "768",
26376             wikidata: "Q945",
26377             nameEn: "Togo",
26378             groups: ["011", "202", "002", "UN"],
26379             callingCodes: ["228"]
26380           },
26381           geometry: {
26382             type: "MultiPolygon",
26383             coordinates: [[[[0.50388, 11.01011], [-0.13493, 11.14075], [-0.14462, 11.10811], [-0.05733, 11.08628], [-0.0275, 11.11202], [-514e-5, 11.10763], [342e-5, 11.08317], [0.02395, 11.06229], [0.03355, 10.9807], [-63e-4, 10.96417], [-908e-5, 10.91644], [-0.02685, 10.8783], [-0.0228, 10.81916], [-0.07183, 10.76794], [-0.07327, 10.71845], [-0.09141, 10.7147], [-0.05945, 10.63458], [0.12886, 10.53149], [0.18846, 10.4096], [0.29453, 10.41546], [0.33028, 10.30408], [0.39584, 10.31112], [0.35293, 10.09412], [0.41371, 10.06361], [0.41252, 10.02018], [0.36366, 10.03309], [0.32075, 9.72781], [0.34816, 9.71607], [0.34816, 9.66907], [0.32313, 9.6491], [0.28261, 9.69022], [0.26712, 9.66437], [0.29334, 9.59387], [0.36008, 9.6256], [0.38153, 9.58682], [0.23851, 9.57389], [0.2409, 9.52335], [0.30406, 9.521], [0.31241, 9.50337], [0.2254, 9.47869], [0.25758, 9.42696], [0.33148, 9.44812], [0.36485, 9.49749], [0.49118, 9.48339], [0.56388, 9.40697], [0.45424, 9.04581], [0.52455, 8.87746], [0.37319, 8.75262], [0.47211, 8.59945], [0.64731, 8.48866], [0.73432, 8.29529], [0.63897, 8.25873], [0.5913, 8.19622], [0.61156, 8.18324], [0.6056, 8.13959], [0.58891, 8.12779], [0.62943, 7.85751], [0.58295, 7.62368], [0.51979, 7.58706], [0.52455, 7.45354], [0.57223, 7.39326], [0.62943, 7.41099], [0.65327, 7.31643], [0.59606, 7.01252], [0.52217, 6.9723], [0.52098, 6.94391], [0.56508, 6.92971], [0.52853, 6.82921], [0.57406, 6.80348], [0.58176, 6.76049], [0.6497, 6.73682], [0.63659, 6.63857], [0.74862, 6.56517], [0.71048, 6.53083], [0.89283, 6.33779], [0.99652, 6.33779], [1.03108, 6.24064], [1.05969, 6.22998], [1.09187, 6.17074], [1.19966, 6.17069], [1.19771, 6.11522], [1.27574, 5.93551], [1.67336, 6.02702], [1.62913, 6.24075], [1.79826, 6.28221], [1.76906, 6.43189], [1.58105, 6.68619], [1.61812, 6.74843], [1.55877, 6.99737], [1.64249, 6.99562], [1.61838, 9.0527], [1.5649, 9.16941], [1.41746, 9.3226], [1.33675, 9.54765], [1.36624, 9.5951], [1.35507, 9.99525], [0.77666, 10.37665], [0.80358, 10.71459], [0.8804, 10.803], [0.91245, 10.99597], [0.66104, 10.99964], [0.4958, 10.93269], [0.50521, 10.98035], [0.48852, 10.98561], [0.50388, 11.01011]]]]
26384           }
26385         }, {
26386           type: "Feature",
26387           properties: {
26388             iso1A2: "TH",
26389             iso1A3: "THA",
26390             iso1N3: "764",
26391             wikidata: "Q869",
26392             nameEn: "Thailand",
26393             groups: ["035", "142", "UN"],
26394             driveSide: "left",
26395             callingCodes: ["66"]
26396           },
26397           geometry: {
26398             type: "MultiPolygon",
26399             coordinates: [[[[100.08404, 20.36626], [99.95721, 20.46301], [99.91616, 20.44986], [99.90499, 20.4487], [99.89692, 20.44789], [99.89301, 20.44311], [99.89168, 20.44548], [99.88451, 20.44596], [99.88211, 20.44488], [99.86383, 20.44371], [99.81096, 20.33687], [99.68255, 20.32077], [99.46008, 20.39673], [99.46077, 20.36198], [99.5569, 20.20676], [99.52943, 20.14811], [99.416, 20.08614], [99.20328, 20.12877], [99.0735, 20.10298], [98.98679, 19.7419], [98.83661, 19.80931], [98.56065, 19.67807], [98.51182, 19.71303], [98.24884, 19.67876], [98.13829, 19.78541], [98.03314, 19.80941], [98.04364, 19.65755], [97.84715, 19.55782], [97.88423, 19.5041], [97.78769, 19.39429], [97.84186, 19.29526], [97.78606, 19.26769], [97.84024, 19.22217], [97.83479, 19.09972], [97.73797, 19.04261], [97.73654, 18.9812], [97.66487, 18.9371], [97.73836, 18.88478], [97.76752, 18.58097], [97.5258, 18.4939], [97.36444, 18.57138], [97.34522, 18.54596], [97.50383, 18.26844], [97.56219, 18.33885], [97.64116, 18.29778], [97.60841, 18.23846], [97.73723, 17.97912], [97.66794, 17.88005], [97.76407, 17.71595], [97.91829, 17.54504], [98.11185, 17.36829], [98.10439, 17.33847], [98.34566, 17.04822], [98.39441, 17.06266], [98.52624, 16.89979], [98.49603, 16.8446], [98.53833, 16.81934], [98.46994, 16.73613], [98.50253, 16.7139], [98.49713, 16.69022], [98.51043, 16.70107], [98.51579, 16.69433], [98.51472, 16.68521], [98.51833, 16.676], [98.51113, 16.64503], [98.5695, 16.62826], [98.57912, 16.55983], [98.63817, 16.47424], [98.68074, 16.27068], [98.84485, 16.42354], [98.92656, 16.36425], [98.8376, 16.11706], [98.69585, 16.13353], [98.57019, 16.04578], [98.59853, 15.87197], [98.541, 15.65406], [98.58598, 15.46821], [98.56027, 15.33471], [98.4866, 15.39154], [98.39351, 15.34177], [98.41906, 15.27103], [98.40522, 15.25268], [98.30446, 15.30667], [98.22, 15.21327], [98.18821, 15.13125], [98.24874, 14.83013], [98.56762, 14.37701], [98.97356, 14.04868], [99.16695, 13.72621], [99.20617, 13.20575], [99.12225, 13.19847], [99.10646, 13.05804], [99.18748, 12.9898], [99.18905, 12.84799], [99.29254, 12.68921], [99.409, 12.60603], [99.47519, 12.1353], [99.56445, 12.14805], [99.53424, 12.02317], [99.64891, 11.82699], [99.64108, 11.78948], [99.5672, 11.62732], [99.47598, 11.62434], [99.39485, 11.3925], [99.31573, 11.32081], [99.32756, 11.28545], [99.06938, 10.94857], [99.02337, 10.97217], [98.99701, 10.92962], [99.0069, 10.85485], [98.86819, 10.78336], [98.78511, 10.68351], [98.77275, 10.62548], [98.81944, 10.52761], [98.7391, 10.31488], [98.55174, 9.92804], [98.52291, 9.92389], [98.47298, 9.95782], [98.33094, 9.91973], [98.12555, 9.44056], [97.63455, 9.60854], [97.19814, 8.18901], [99.31854, 5.99868], [99.50117, 6.44501], [99.91873, 6.50233], [100.0756, 6.4045], [100.12, 6.42105], [100.19511, 6.72559], [100.29651, 6.68439], [100.30828, 6.66462], [100.31618, 6.66781], [100.31884, 6.66423], [100.32671, 6.66526], [100.32607, 6.65933], [100.31929, 6.65413], [100.35413, 6.54932], [100.41152, 6.52299], [100.41791, 6.5189], [100.42351, 6.51762], [100.43027, 6.52389], [100.66986, 6.45086], [100.74361, 6.50811], [100.74822, 6.46231], [100.81045, 6.45086], [100.85884, 6.24929], [101.10313, 6.25617], [101.12618, 6.19431], [101.06165, 6.14161], [101.12388, 6.11411], [101.087, 5.9193], [101.02708, 5.91013], [100.98815, 5.79464], [101.14062, 5.61613], [101.25755, 5.71065], [101.25524, 5.78633], [101.58019, 5.93534], [101.69773, 5.75881], [101.75074, 5.79091], [101.80144, 5.74505], [101.89188, 5.8386], [101.91776, 5.84269], [101.92819, 5.85511], [101.94712, 5.98421], [101.9714, 6.00575], [101.97114, 6.01992], [101.99209, 6.04075], [102.01835, 6.05407], [102.09182, 6.14161], [102.07732, 6.193], [102.08127, 6.22679], [102.09086, 6.23546], [102.46318, 7.22462], [102.47649, 9.66162], [102.52395, 11.25257], [102.91449, 11.65512], [102.90973, 11.75613], [102.83957, 11.8519], [102.78427, 11.98746], [102.77026, 12.06815], [102.70176, 12.1686], [102.73134, 12.37091], [102.78116, 12.40284], [102.7796, 12.43781], [102.57567, 12.65358], [102.51963, 12.66117], [102.4994, 12.71736], [102.53053, 12.77506], [102.49335, 12.92711], [102.48694, 12.97537], [102.52275, 12.99813], [102.46011, 13.08057], [102.43422, 13.09061], [102.36146, 13.26006], [102.36001, 13.31142], [102.34611, 13.35618], [102.35692, 13.38274], [102.35563, 13.47307], [102.361, 13.50551], [102.33828, 13.55613], [102.36859, 13.57488], [102.44601, 13.5637], [102.5358, 13.56933], [102.57573, 13.60461], [102.62483, 13.60883], [102.58635, 13.6286], [102.5481, 13.6589], [102.56848, 13.69366], [102.72727, 13.77806], [102.77864, 13.93374], [102.91251, 14.01531], [102.93275, 14.19044], [103.16469, 14.33075], [103.39353, 14.35639], [103.53518, 14.42575], [103.71109, 14.4348], [103.70175, 14.38052], [103.93836, 14.3398], [104.27616, 14.39861], [104.55014, 14.36091], [104.69335, 14.42726], [104.97667, 14.38806], [105.02804, 14.23722], [105.08408, 14.20402], [105.14012, 14.23873], [105.17748, 14.34432], [105.20894, 14.34967], [105.43783, 14.43865], [105.53864, 14.55731], [105.5121, 14.80802], [105.61162, 15.00037], [105.46661, 15.13132], [105.58043, 15.32724], [105.50662, 15.32054], [105.4692, 15.33709], [105.47635, 15.3796], [105.58191, 15.41031], [105.60446, 15.53301], [105.61756, 15.68792], [105.46573, 15.74742], [105.42285, 15.76971], [105.37959, 15.84074], [105.34115, 15.92737], [105.38508, 15.987], [105.42001, 16.00657], [105.06204, 16.09792], [105.00262, 16.25627], [104.88057, 16.37311], [104.73349, 16.565], [104.76099, 16.69302], [104.7397, 16.81005], [104.76442, 16.84752], [104.7373, 16.91125], [104.73712, 17.01404], [104.80716, 17.19025], [104.80061, 17.39367], [104.69867, 17.53038], [104.45404, 17.66788], [104.35432, 17.82871], [104.2757, 17.86139], [104.21776, 17.99335], [104.10927, 18.10826], [104.06533, 18.21656], [103.97725, 18.33631], [103.93916, 18.33914], [103.85642, 18.28666], [103.82449, 18.33979], [103.699, 18.34125], [103.60957, 18.40528], [103.47773, 18.42841], [103.41044, 18.4486], [103.30977, 18.4341], [103.24779, 18.37807], [103.23818, 18.34875], [103.29757, 18.30475], [103.17093, 18.2618], [103.14994, 18.23172], [103.1493, 18.17799], [103.07343, 18.12351], [103.07823, 18.03833], [103.0566, 18.00144], [103.01998, 17.97095], [102.9912, 17.9949], [102.95812, 18.0054], [102.86323, 17.97531], [102.81988, 17.94233], [102.79044, 17.93612], [102.75954, 17.89561], [102.68538, 17.86653], [102.67543, 17.84529], [102.69946, 17.81686], [102.68194, 17.80151], [102.59485, 17.83537], [102.5896, 17.84889], [102.61432, 17.92273], [102.60971, 17.95411], [102.59234, 17.96127], [102.45523, 17.97106], [102.11359, 18.21532], [101.88485, 18.02474], [101.78087, 18.07559], [101.72294, 17.92867], [101.44667, 17.7392], [101.15108, 17.47586], [100.96541, 17.57926], [101.02185, 17.87637], [101.1793, 18.0544], [101.19118, 18.2125], [101.15108, 18.25624], [101.18227, 18.34367], [101.06047, 18.43247], [101.27585, 18.68875], [101.22832, 18.73377], [101.25803, 18.89545], [101.35606, 19.04716], [101.261, 19.12717], [101.24911, 19.33334], [101.20604, 19.35296], [101.21347, 19.46223], [101.26991, 19.48324], [101.26545, 19.59242], [101.08928, 19.59748], [100.90302, 19.61901], [100.77231, 19.48324], [100.64606, 19.55884], [100.58219, 19.49164], [100.49604, 19.53504], [100.398, 19.75047], [100.5094, 19.87904], [100.58808, 20.15791], [100.55218, 20.17741], [100.51052, 20.14928], [100.47567, 20.19133], [100.4537, 20.19971], [100.44992, 20.23644], [100.41473, 20.25625], [100.37439, 20.35156], [100.33383, 20.4028], [100.25769, 20.3992], [100.22076, 20.31598], [100.16668, 20.2986], [100.1712, 20.24324], [100.11785, 20.24787], [100.09337, 20.26293], [100.09999, 20.31614], [100.08404, 20.36626]]]]
26400           }
26401         }, {
26402           type: "Feature",
26403           properties: {
26404             iso1A2: "TJ",
26405             iso1A3: "TJK",
26406             iso1N3: "762",
26407             wikidata: "Q863",
26408             nameEn: "Tajikistan",
26409             groups: ["143", "142", "UN"],
26410             callingCodes: ["992"]
26411           },
26412           geometry: {
26413             type: "MultiPolygon",
26414             coordinates: [[[[70.45251, 41.04438], [70.38028, 41.02014], [70.36655, 40.90296], [69.69434, 40.62615], [69.59441, 40.70181], [69.53021, 40.77621], [69.38327, 40.7918], [69.32834, 40.70233], [69.3455, 40.57988], [69.2643, 40.57506], [69.21063, 40.54469], [69.27066, 40.49274], [69.28525, 40.41894], [69.30774, 40.36102], [69.33794, 40.34819], [69.32833, 40.29794], [69.30808, 40.2821], [69.24817, 40.30357], [69.25229, 40.26362], [69.30104, 40.24502], [69.30448, 40.18774], [69.2074, 40.21488], [69.15659, 40.2162], [69.04544, 40.22904], [68.85832, 40.20885], [68.84357, 40.18604], [68.79276, 40.17555], [68.77902, 40.20492], [68.5332, 40.14826], [68.52771, 40.11676], [68.62796, 40.07789], [69.01523, 40.15771], [69.01935, 40.11466], [68.96579, 40.06949], [68.84906, 40.04952], [68.93695, 39.91167], [68.88889, 39.87163], [68.63071, 39.85265], [68.61972, 39.68905], [68.54166, 39.53929], [68.12053, 39.56317], [67.70992, 39.66156], [67.62889, 39.60234], [67.44899, 39.57799], [67.46547, 39.53564], [67.39681, 39.52505], [67.46822, 39.46146], [67.45998, 39.315], [67.36522, 39.31287], [67.33226, 39.23739], [67.67833, 39.14479], [67.68915, 39.00775], [68.09704, 39.02589], [68.19743, 38.85985], [68.06948, 38.82115], [68.12877, 38.73677], [68.05598, 38.71641], [68.0807, 38.64136], [68.05873, 38.56087], [68.11366, 38.47169], [68.06274, 38.39435], [68.13289, 38.40822], [68.40343, 38.19484], [68.27159, 37.91477], [68.12635, 37.93], [67.81566, 37.43107], [67.8474, 37.31594], [67.78329, 37.1834], [67.7803, 37.08978], [67.87917, 37.0591], [68.02194, 36.91923], [68.18542, 37.02074], [68.27605, 37.00977], [68.29253, 37.10621], [68.41201, 37.10402], [68.41888, 37.13906], [68.61851, 37.19815], [68.6798, 37.27906], [68.81438, 37.23862], [68.80889, 37.32494], [68.91189, 37.26704], [68.88168, 37.33368], [68.96407, 37.32603], [69.03274, 37.25174], [69.25152, 37.09426], [69.39529, 37.16752], [69.45022, 37.23315], [69.36645, 37.40462], [69.44954, 37.4869], [69.51888, 37.5844], [69.80041, 37.5746], [69.84435, 37.60616], [69.93362, 37.61378], [69.95971, 37.5659], [70.15015, 37.52519], [70.28243, 37.66706], [70.27694, 37.81258], [70.1863, 37.84296], [70.17206, 37.93276], [70.4898, 38.12546], [70.54673, 38.24541], [70.60407, 38.28046], [70.61526, 38.34774], [70.64966, 38.34999], [70.69189, 38.37031], [70.6761, 38.39144], [70.67438, 38.40597], [70.69807, 38.41861], [70.72485, 38.4131], [70.75455, 38.4252], [70.77132, 38.45548], [70.78581, 38.45502], [70.78702, 38.45031], [70.79766, 38.44944], [70.80521, 38.44447], [70.81697, 38.44507], [70.82538, 38.45394], [70.84376, 38.44688], [70.88719, 38.46826], [70.92728, 38.43021], [70.98693, 38.48862], [71.03545, 38.44779], [71.0556, 38.40176], [71.09542, 38.42517], [71.10592, 38.42077], [71.10957, 38.40671], [71.1451, 38.40106], [71.21291, 38.32797], [71.33114, 38.30339], [71.33869, 38.27335], [71.37803, 38.25641], [71.36444, 38.15358], [71.29878, 38.04429], [71.28922, 38.01272], [71.27622, 37.99946], [71.27278, 37.96496], [71.24969, 37.93031], [71.2809, 37.91995], [71.296, 37.93403], [71.32871, 37.88564], [71.51565, 37.95349], [71.58843, 37.92425], [71.59255, 37.79956], [71.55752, 37.78677], [71.54324, 37.77104], [71.53053, 37.76534], [71.55234, 37.73209], [71.54186, 37.69691], [71.51972, 37.61945], [71.5065, 37.60912], [71.49693, 37.53527], [71.50616, 37.50733], [71.5256, 37.47971], [71.49612, 37.4279], [71.47685, 37.40281], [71.4862, 37.33405], [71.49821, 37.31975], [71.50674, 37.31502], [71.48536, 37.26017], [71.4824, 37.24921], [71.48339, 37.23937], [71.47386, 37.2269], [71.4555, 37.21418], [71.4494, 37.18137], [71.44127, 37.11856], [71.43097, 37.05855], [71.45578, 37.03094], [71.46923, 36.99925], [71.48481, 36.93218], [71.51502, 36.89128], [71.57195, 36.74943], [71.67083, 36.67346], [71.83229, 36.68084], [72.31676, 36.98115], [72.54095, 37.00007], [72.66381, 37.02014], [72.79693, 37.22222], [73.06884, 37.31729], [73.29633, 37.46495], [73.77197, 37.4417], [73.76647, 37.33913], [73.61129, 37.27469], [73.64974, 37.23643], [73.82552, 37.22659], [73.8564, 37.26158], [74.20308, 37.34208], [74.23339, 37.41116], [74.41055, 37.3948], [74.56161, 37.37734], [74.68383, 37.3948], [74.8294, 37.3435], [74.88887, 37.23275], [75.12328, 37.31839], [75.09719, 37.37297], [75.15899, 37.41443], [75.06011, 37.52779], [74.94338, 37.55501], [74.8912, 37.67576], [75.00935, 37.77486], [74.92416, 37.83428], [74.9063, 38.03033], [74.82665, 38.07359], [74.80331, 38.19889], [74.69894, 38.22155], [74.69619, 38.42947], [74.51217, 38.47034], [74.17022, 38.65504], [73.97933, 38.52945], [73.79806, 38.61106], [73.80656, 38.66449], [73.7033, 38.84782], [73.7445, 38.93867], [73.82964, 38.91517], [73.81728, 39.04007], [73.75823, 39.023], [73.60638, 39.24534], [73.54572, 39.27567], [73.55396, 39.3543], [73.5004, 39.38402], [73.59241, 39.40843], [73.59831, 39.46425], [73.45096, 39.46677], [73.31912, 39.38615], [73.18454, 39.35536], [72.85934, 39.35116], [72.62027, 39.39696], [72.33173, 39.33093], [72.23834, 39.17248], [72.17242, 39.2661], [72.09689, 39.26823], [72.04059, 39.36704], [71.90601, 39.27674], [71.79202, 39.27355], [71.7522, 39.32031], [71.80164, 39.40631], [71.76816, 39.45456], [71.62688, 39.44056], [71.5517, 39.45722], [71.55856, 39.57588], [71.49814, 39.61397], [71.08752, 39.50704], [71.06418, 39.41586], [70.7854, 39.38933], [70.64087, 39.58792], [70.44757, 39.60128], [70.2869, 39.53141], [70.11111, 39.58223], [69.87491, 39.53882], [69.68677, 39.59281], [69.3594, 39.52516], [69.26938, 39.8127], [69.35649, 40.01994], [69.43134, 39.98431], [69.43557, 39.92877], [69.53615, 39.93991], [69.5057, 40.03277], [69.53855, 40.0887], [69.53794, 40.11833], [69.55555, 40.12296], [69.57615, 40.10524], [69.64704, 40.12165], [69.67001, 40.10639], [70.01283, 40.23288], [70.58297, 40.00891], [70.57384, 39.99394], [70.47557, 39.93216], [70.55033, 39.96619], [70.58912, 39.95211], [70.65946, 39.9878], [70.65827, 40.0981], [70.7928, 40.12797], [70.80495, 40.16813], [70.9818, 40.22392], [70.8607, 40.217], [70.62342, 40.17396], [70.56394, 40.26421], [70.57149, 40.3442], [70.37511, 40.38605], [70.32626, 40.45174], [70.49871, 40.52503], [70.80009, 40.72825], [70.45251, 41.04438]]], [[[70.68112, 40.90612], [70.6158, 40.97661], [70.56077, 41.00642], [70.54223, 40.98787], [70.57501, 40.98941], [70.6721, 40.90555], [70.68112, 40.90612]]], [[[70.74189, 39.86319], [70.53651, 39.89155], [70.52631, 39.86989], [70.54998, 39.85137], [70.59667, 39.83542], [70.63105, 39.77923], [70.74189, 39.86319]]]]
26415           }
26416         }, {
26417           type: "Feature",
26418           properties: {
26419             iso1A2: "TK",
26420             iso1A3: "TKL",
26421             iso1N3: "772",
26422             wikidata: "Q36823",
26423             nameEn: "Tokelau",
26424             country: "NZ",
26425             groups: ["061", "009", "UN"],
26426             driveSide: "left",
26427             callingCodes: ["690"]
26428           },
26429           geometry: {
26430             type: "MultiPolygon",
26431             coordinates: [[[[-168.251, -9.44289], [-174.18635, -7.80441], [-174.17993, -10.13616], [-168.251, -9.44289]]]]
26432           }
26433         }, {
26434           type: "Feature",
26435           properties: {
26436             iso1A2: "TL",
26437             iso1A3: "TLS",
26438             iso1N3: "626",
26439             wikidata: "Q574",
26440             nameEn: "East Timor",
26441             aliases: ["Timor-Leste", "TP"],
26442             groups: ["035", "142", "UN"],
26443             driveSide: "left",
26444             callingCodes: ["670"]
26445           },
26446           geometry: {
26447             type: "MultiPolygon",
26448             coordinates: [[[[124.46701, -9.13002], [124.94011, -8.85617], [124.97742, -9.08128], [125.11764, -8.96359], [125.18632, -9.03142], [125.18907, -9.16434], [125.09434, -9.19669], [125.04044, -9.17093], [124.97892, -9.19281], [125.09025, -9.46406], [125.68138, -9.85176], [127.55165, -9.05052], [127.42116, -8.22471], [125.87691, -8.31789], [125.58506, -7.95311], [124.92337, -8.75859], [124.33472, -9.11416], [124.04628, -9.22671], [124.04286, -9.34243], [124.10539, -9.41206], [124.14517, -9.42324], [124.21247, -9.36904], [124.28115, -9.42189], [124.28115, -9.50453], [124.3535, -9.48493], [124.35258, -9.43002], [124.38554, -9.3582], [124.45971, -9.30263], [124.46701, -9.13002]]]]
26449           }
26450         }, {
26451           type: "Feature",
26452           properties: {
26453             iso1A2: "TM",
26454             iso1A3: "TKM",
26455             iso1N3: "795",
26456             wikidata: "Q874",
26457             nameEn: "Turkmenistan",
26458             groups: ["143", "142", "UN"],
26459             callingCodes: ["993"]
26460           },
26461           geometry: {
26462             type: "MultiPolygon",
26463             coordinates: [[[[60.5078, 41.21694], [60.06581, 41.4363], [60.18117, 41.60082], [60.06032, 41.76287], [60.08504, 41.80997], [60.33223, 41.75058], [59.95046, 41.97966], [60.0356, 42.01028], [60.04659, 42.08982], [59.96419, 42.1428], [60.00539, 42.212], [59.94633, 42.27655], [59.4341, 42.29738], [59.2955, 42.37064], [59.17317, 42.52248], [58.93422, 42.5407], [58.6266, 42.79314], [58.57991, 42.64988], [58.27504, 42.69632], [58.14321, 42.62159], [58.29427, 42.56497], [58.51674, 42.30348], [58.40688, 42.29535], [58.3492, 42.43335], [57.99214, 42.50021], [57.90975, 42.4374], [57.92897, 42.24047], [57.84932, 42.18555], [57.6296, 42.16519], [57.30275, 42.14076], [57.03633, 41.92043], [56.96218, 41.80383], [57.03359, 41.41777], [57.13796, 41.36625], [57.03423, 41.25435], [56.00314, 41.32584], [55.45471, 41.25609], [54.95182, 41.92424], [54.20635, 42.38477], [52.97575, 42.1308], [52.47884, 41.78034], [52.26048, 41.69249], [51.7708, 40.29239], [53.89734, 37.3464], [54.24565, 37.32047], [54.36211, 37.34912], [54.58664, 37.45809], [54.67247, 37.43532], [54.77822, 37.51597], [54.81804, 37.61285], [54.77684, 37.62264], [54.851, 37.75739], [55.13412, 37.94705], [55.44152, 38.08564], [55.76561, 38.12238], [55.97847, 38.08024], [56.33278, 38.08132], [56.32454, 38.18502], [56.43303, 38.26054], [56.62255, 38.24005], [56.73928, 38.27887], [57.03453, 38.18717], [57.21169, 38.28965], [57.37236, 38.09321], [57.35042, 37.98546], [57.79534, 37.89299], [58.21399, 37.77281], [58.22999, 37.6856], [58.39959, 37.63134], [58.47786, 37.6433], [58.5479, 37.70526], [58.6921, 37.64548], [58.9338, 37.67374], [59.22905, 37.51161], [59.33507, 37.53146], [59.39797, 37.47892], [59.39385, 37.34257], [59.55178, 37.13594], [59.74678, 37.12499], [60.00768, 37.04102], [60.34767, 36.63214], [61.14516, 36.64644], [61.18187, 36.55348], [61.1393, 36.38782], [61.22719, 36.12759], [61.12007, 35.95992], [61.22444, 35.92879], [61.26152, 35.80749], [61.22719, 35.67038], [61.27371, 35.61482], [61.58742, 35.43803], [61.77693, 35.41341], [61.97743, 35.4604], [62.05709, 35.43803], [62.15871, 35.33278], [62.29191, 35.25964], [62.29878, 35.13312], [62.48006, 35.28796], [62.62288, 35.22067], [62.74098, 35.25432], [62.90853, 35.37086], [63.0898, 35.43131], [63.12276, 35.53196], [63.10079, 35.63024], [63.23262, 35.67487], [63.10318, 35.81782], [63.12276, 35.86208], [63.29579, 35.85985], [63.53475, 35.90881], [63.56496, 35.95106], [63.98519, 36.03773], [64.05385, 36.10433], [64.43288, 36.24401], [64.57295, 36.34362], [64.62514, 36.44311], [64.61141, 36.6351], [64.97945, 37.21913], [65.51778, 37.23881], [65.64263, 37.34388], [65.64137, 37.45061], [65.72274, 37.55438], [66.30993, 37.32409], [66.55743, 37.35409], [66.52303, 37.39827], [66.65761, 37.45497], [66.52852, 37.58568], [66.53676, 37.80084], [66.67684, 37.96776], [66.56697, 38.0435], [66.41042, 38.02403], [66.24013, 38.16238], [65.83913, 38.25733], [65.55873, 38.29052], [64.32576, 38.98691], [64.19086, 38.95561], [63.70778, 39.22349], [63.6913, 39.27666], [62.43337, 39.98528], [62.34273, 40.43206], [62.11751, 40.58242], [61.87856, 41.12257], [61.4446, 41.29407], [61.39732, 41.19873], [61.33199, 41.14946], [61.22212, 41.14946], [61.03261, 41.25691], [60.5078, 41.21694]]]]
26464           }
26465         }, {
26466           type: "Feature",
26467           properties: {
26468             iso1A2: "TN",
26469             iso1A3: "TUN",
26470             iso1N3: "788",
26471             wikidata: "Q948",
26472             nameEn: "Tunisia",
26473             groups: ["015", "002", "UN"],
26474             callingCodes: ["216"]
26475           },
26476           geometry: {
26477             type: "MultiPolygon",
26478             coordinates: [[[[11.2718, 37.6713], [7.89009, 38.19924], [8.59123, 37.14286], [8.64044, 36.9401], [8.62972, 36.86499], [8.67706, 36.8364], [8.57613, 36.78062], [8.46537, 36.7706], [8.47609, 36.66607], [8.16167, 36.48817], [8.18936, 36.44939], [8.40731, 36.42208], [8.2626, 35.91733], [8.26472, 35.73669], [8.35371, 35.66373], [8.36086, 35.47774], [8.30329, 35.29884], [8.47318, 35.23376], [8.3555, 35.10007], [8.30727, 34.95378], [8.25189, 34.92009], [8.29655, 34.72798], [8.20482, 34.57575], [7.86264, 34.3987], [7.81242, 34.21841], [7.74207, 34.16492], [7.66174, 34.20167], [7.52851, 34.06493], [7.54088, 33.7726], [7.73687, 33.42114], [7.83028, 33.18851], [8.11433, 33.10175], [8.1179, 33.05086], [8.31895, 32.83483], [8.35999, 32.50101], [9.07483, 32.07865], [9.55544, 30.23971], [9.76848, 30.34366], [9.88152, 30.34074], [10.29516, 30.90337], [10.12239, 31.42098], [10.31364, 31.72648], [10.48497, 31.72956], [10.62788, 31.96629], [10.7315, 31.97235], [11.04234, 32.2145], [11.53898, 32.4138], [11.57828, 32.48013], [11.46037, 32.6307], [11.51549, 33.09826], [11.55852, 33.1409], [11.58941, 33.36891], [11.2718, 37.6713]]]]
26479           }
26480         }, {
26481           type: "Feature",
26482           properties: {
26483             iso1A2: "TO",
26484             iso1A3: "TON",
26485             iso1N3: "776",
26486             wikidata: "Q678",
26487             nameEn: "Tonga",
26488             groups: ["061", "009", "UN"],
26489             driveSide: "left",
26490             callingCodes: ["676"]
26491           },
26492           geometry: {
26493             type: "MultiPolygon",
26494             coordinates: [[[[-176.74538, -22.89767], [-180, -22.90585], [-180, -24.21376], [-173.10761, -24.19665], [-173.13438, -14.94228], [-176.76826, -14.95183], [-176.74538, -22.89767]]]]
26495           }
26496         }, {
26497           type: "Feature",
26498           properties: {
26499             iso1A2: "TR",
26500             iso1A3: "TUR",
26501             iso1N3: "792",
26502             wikidata: "Q43",
26503             nameEn: "Turkey",
26504             groups: ["145", "142", "UN"],
26505             callingCodes: ["90"]
26506           },
26507           geometry: {
26508             type: "MultiPolygon",
26509             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]]]]
26510           }
26511         }, {
26512           type: "Feature",
26513           properties: {
26514             iso1A2: "TT",
26515             iso1A3: "TTO",
26516             iso1N3: "780",
26517             wikidata: "Q754",
26518             nameEn: "Trinidad and Tobago",
26519             groups: ["029", "003", "419", "019", "UN"],
26520             driveSide: "left",
26521             callingCodes: ["1 868"]
26522           },
26523           geometry: {
26524             type: "MultiPolygon",
26525             coordinates: [[[[-61.62505, 11.18974], [-62.08693, 10.04435], [-60.89962, 9.81445], [-60.07172, 11.77667], [-61.62505, 11.18974]]]]
26526           }
26527         }, {
26528           type: "Feature",
26529           properties: {
26530             iso1A2: "TV",
26531             iso1A3: "TUV",
26532             iso1N3: "798",
26533             wikidata: "Q672",
26534             nameEn: "Tuvalu",
26535             groups: ["061", "009", "UN"],
26536             driveSide: "left",
26537             callingCodes: ["688"]
26538           },
26539           geometry: {
26540             type: "MultiPolygon",
26541             coordinates: [[[[174, -5], [174, -11.5], [179.99999, -11.5], [179.99999, -5], [174, -5]]]]
26542           }
26543         }, {
26544           type: "Feature",
26545           properties: {
26546             iso1A2: "TW",
26547             iso1A3: "TWN",
26548             iso1N3: "158",
26549             wikidata: "Q865",
26550             nameEn: "Taiwan",
26551             aliases: ["RC"],
26552             groups: ["030", "142"],
26553             callingCodes: ["886"]
26554           },
26555           geometry: {
26556             type: "MultiPolygon",
26557             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]]]]
26558           }
26559         }, {
26560           type: "Feature",
26561           properties: {
26562             iso1A2: "TZ",
26563             iso1A3: "TZA",
26564             iso1N3: "834",
26565             wikidata: "Q924",
26566             nameEn: "Tanzania",
26567             groups: ["014", "202", "002", "UN"],
26568             driveSide: "left",
26569             callingCodes: ["255"]
26570           },
26571           geometry: {
26572             type: "MultiPolygon",
26573             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]]]]
26574           }
26575         }, {
26576           type: "Feature",
26577           properties: {
26578             iso1A2: "UA",
26579             iso1A3: "UKR",
26580             iso1N3: "804",
26581             wikidata: "Q212",
26582             nameEn: "Ukraine",
26583             groups: ["151", "150", "UN"],
26584             callingCodes: ["380"]
26585           },
26586           geometry: {
26587             type: "MultiPolygon",
26588             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]]]]
26589           }
26590         }, {
26591           type: "Feature",
26592           properties: {
26593             iso1A2: "UG",
26594             iso1A3: "UGA",
26595             iso1N3: "800",
26596             wikidata: "Q1036",
26597             nameEn: "Uganda",
26598             groups: ["014", "202", "002", "UN"],
26599             driveSide: "left",
26600             callingCodes: ["256"]
26601           },
26602           geometry: {
26603             type: "MultiPolygon",
26604             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]]]]
26605           }
26606         }, {
26607           type: "Feature",
26608           properties: {
26609             iso1A2: "UM",
26610             iso1A3: "UMI",
26611             iso1N3: "581",
26612             wikidata: "Q16645",
26613             nameEn: "United States Minor Outlying Islands",
26614             country: "US"
26615           },
26616           geometry: null
26617         }, {
26618           type: "Feature",
26619           properties: {
26620             iso1A2: "UN",
26621             wikidata: "Q1065",
26622             nameEn: "United Nations",
26623             level: "unitedNations",
26624             isoStatus: "excRes"
26625           },
26626           geometry: null
26627         }, {
26628           type: "Feature",
26629           properties: {
26630             iso1A2: "US",
26631             iso1A3: "USA",
26632             iso1N3: "840",
26633             wikidata: "Q30",
26634             nameEn: "United States of America"
26635           },
26636           geometry: null
26637         }, {
26638           type: "Feature",
26639           properties: {
26640             iso1A2: "UY",
26641             iso1A3: "URY",
26642             iso1N3: "858",
26643             wikidata: "Q77",
26644             nameEn: "Uruguay",
26645             groups: ["005", "419", "019", "UN"],
26646             callingCodes: ["598"]
26647           },
26648           geometry: {
26649             type: "MultiPolygon",
26650             coordinates: [[[[-57.65132, -30.19229], [-57.61478, -30.25165], [-57.64859, -30.35095], [-57.89115, -30.49572], [-57.8024, -30.77193], [-57.89476, -30.95994], [-57.86729, -31.06352], [-57.9908, -31.34924], [-57.98127, -31.3872], [-58.07569, -31.44916], [-58.0023, -31.53084], [-58.00076, -31.65016], [-58.20252, -31.86966], [-58.10036, -32.25338], [-58.22362, -32.52416], [-58.1224, -32.98842], [-58.40475, -33.11777], [-58.44442, -33.84033], [-58.34425, -34.15035], [-57.83001, -34.69099], [-54.78916, -36.21945], [-52.83257, -34.01481], [-53.37138, -33.74313], [-53.39593, -33.75169], [-53.44031, -33.69344], [-53.52794, -33.68908], [-53.53459, -33.16843], [-53.1111, -32.71147], [-53.37671, -32.57005], [-53.39572, -32.58596], [-53.76024, -32.0751], [-54.17384, -31.86168], [-55.50821, -30.91349], [-55.50841, -30.9027], [-55.51862, -30.89828], [-55.52712, -30.89997], [-55.53276, -30.90218], [-55.53431, -30.89714], [-55.54572, -30.89051], [-55.55218, -30.88193], [-55.55373, -30.8732], [-55.5634, -30.8686], [-55.58866, -30.84117], [-55.87388, -31.05053], [-56.4619, -30.38457], [-56.4795, -30.3899], [-56.49267, -30.39471], [-56.90236, -30.02578], [-57.22502, -30.26121], [-57.65132, -30.19229]]]]
26651           }
26652         }, {
26653           type: "Feature",
26654           properties: {
26655             iso1A2: "UZ",
26656             iso1A3: "UZB",
26657             iso1N3: "860",
26658             wikidata: "Q265",
26659             nameEn: "Uzbekistan",
26660             groups: ["143", "142", "UN"],
26661             callingCodes: ["998"]
26662           },
26663           geometry: {
26664             type: "MultiPolygon",
26665             coordinates: [[[[65.85194, 42.85481], [65.53277, 43.31856], [65.18666, 43.48835], [64.96464, 43.74748], [64.53885, 43.56941], [63.34656, 43.64003], [62.01711, 43.51008], [61.01475, 44.41383], [58.59711, 45.58671], [55.97842, 44.99622], [55.97832, 44.99622], [55.97822, 44.99617], [55.97811, 44.99617], [55.97801, 44.99612], [55.97801, 44.99607], [55.97791, 44.99607], [55.9778, 44.99607], [55.9777, 44.99601], [55.9777, 44.99596], [55.9776, 44.99591], [55.97749, 44.99591], [55.97739, 44.99591], [55.97739, 44.99586], [55.97729, 44.99586], [55.97718, 44.99581], [55.97708, 44.99576], [55.97698, 44.9957], [55.97698, 44.99565], [55.97687, 44.9956], [55.97677, 44.9956], [55.97677, 44.99555], [55.97677, 44.9955], [55.97667, 44.99545], [55.97656, 44.99539], [55.97646, 44.99534], [55.97646, 44.99529], [55.97636, 44.99524], [55.97636, 44.99519], [55.97625, 44.99514], [55.97615, 44.99508], [55.97615, 44.99503], [55.97615, 44.99498], [55.97615, 44.99493], [55.97615, 44.99483], [55.97615, 44.99477], [55.97605, 44.99477], [55.97605, 44.99467], [55.97605, 44.99462], [55.97605, 44.99457], [55.97605, 44.99452], [55.97594, 44.99446], [55.97584, 44.99441], [55.97584, 44.99436], [55.97584, 44.99431], [55.97584, 44.99426], [55.97584, 44.99421], [55.97584, 44.99415], [55.97584, 44.99405], [55.97584, 44.994], [55.97584, 44.9939], [55.97584, 44.99384], [55.97584, 44.99374], [55.97584, 44.99369], [55.97584, 44.99359], [55.97584, 44.99353], [55.97584, 44.99348], [55.97584, 44.99343], [55.97584, 44.99338], [55.97584, 44.99328], [55.97584, 44.99322], [56.00314, 41.32584], [57.03423, 41.25435], [57.13796, 41.36625], [57.03359, 41.41777], [56.96218, 41.80383], [57.03633, 41.92043], [57.30275, 42.14076], [57.6296, 42.16519], [57.84932, 42.18555], [57.92897, 42.24047], [57.90975, 42.4374], [57.99214, 42.50021], [58.3492, 42.43335], [58.40688, 42.29535], [58.51674, 42.30348], [58.29427, 42.56497], [58.14321, 42.62159], [58.27504, 42.69632], [58.57991, 42.64988], [58.6266, 42.79314], [58.93422, 42.5407], [59.17317, 42.52248], [59.2955, 42.37064], [59.4341, 42.29738], [59.94633, 42.27655], [60.00539, 42.212], [59.96419, 42.1428], [60.04659, 42.08982], [60.0356, 42.01028], [59.95046, 41.97966], [60.33223, 41.75058], [60.08504, 41.80997], [60.06032, 41.76287], [60.18117, 41.60082], [60.06581, 41.4363], [60.5078, 41.21694], [61.03261, 41.25691], [61.22212, 41.14946], [61.33199, 41.14946], [61.39732, 41.19873], [61.4446, 41.29407], [61.87856, 41.12257], [62.11751, 40.58242], [62.34273, 40.43206], [62.43337, 39.98528], [63.6913, 39.27666], [63.70778, 39.22349], [64.19086, 38.95561], [64.32576, 38.98691], [65.55873, 38.29052], [65.83913, 38.25733], [66.24013, 38.16238], [66.41042, 38.02403], [66.56697, 38.0435], [66.67684, 37.96776], [66.53676, 37.80084], [66.52852, 37.58568], [66.65761, 37.45497], [66.52303, 37.39827], [66.55743, 37.35409], [66.64699, 37.32958], [66.95598, 37.40162], [67.08232, 37.35469], [67.13039, 37.27168], [67.2224, 37.24545], [67.2581, 37.17216], [67.51868, 37.26102], [67.78329, 37.1834], [67.8474, 37.31594], [67.81566, 37.43107], [68.12635, 37.93], [68.27159, 37.91477], [68.40343, 38.19484], [68.13289, 38.40822], [68.06274, 38.39435], [68.11366, 38.47169], [68.05873, 38.56087], [68.0807, 38.64136], [68.05598, 38.71641], [68.12877, 38.73677], [68.06948, 38.82115], [68.19743, 38.85985], [68.09704, 39.02589], [67.68915, 39.00775], [67.67833, 39.14479], [67.33226, 39.23739], [67.36522, 39.31287], [67.45998, 39.315], [67.46822, 39.46146], [67.39681, 39.52505], [67.46547, 39.53564], [67.44899, 39.57799], [67.62889, 39.60234], [67.70992, 39.66156], [68.12053, 39.56317], [68.54166, 39.53929], [68.61972, 39.68905], [68.63071, 39.85265], [68.88889, 39.87163], [68.93695, 39.91167], [68.84906, 40.04952], [68.96579, 40.06949], [69.01935, 40.11466], [69.01523, 40.15771], [68.62796, 40.07789], [68.52771, 40.11676], [68.5332, 40.14826], [68.77902, 40.20492], [68.79276, 40.17555], [68.84357, 40.18604], [68.85832, 40.20885], [69.04544, 40.22904], [69.15659, 40.2162], [69.2074, 40.21488], [69.30448, 40.18774], [69.30104, 40.24502], [69.25229, 40.26362], [69.24817, 40.30357], [69.30808, 40.2821], [69.32833, 40.29794], [69.33794, 40.34819], [69.30774, 40.36102], [69.28525, 40.41894], [69.27066, 40.49274], [69.21063, 40.54469], [69.2643, 40.57506], [69.3455, 40.57988], [69.32834, 40.70233], [69.38327, 40.7918], [69.53021, 40.77621], [69.59441, 40.70181], [69.69434, 40.62615], [70.36655, 40.90296], [70.38028, 41.02014], [70.45251, 41.04438], [70.80009, 40.72825], [70.49871, 40.52503], [70.32626, 40.45174], [70.37511, 40.38605], [70.57149, 40.3442], [70.56394, 40.26421], [70.62342, 40.17396], [70.8607, 40.217], [70.9818, 40.22392], [70.95789, 40.28761], [71.05901, 40.28765], [71.13042, 40.34106], [71.36663, 40.31593], [71.4246, 40.28619], [71.51215, 40.26943], [71.51549, 40.22986], [71.61725, 40.20615], [71.61931, 40.26775], [71.68386, 40.26984], [71.70569, 40.20391], [71.69621, 40.18492], [71.71719, 40.17886], [71.73054, 40.14818], [71.82646, 40.21872], [71.85002, 40.25647], [72.05464, 40.27586], [71.96401, 40.31907], [72.18648, 40.49893], [72.24368, 40.46091], [72.40346, 40.4007], [72.44191, 40.48222], [72.41513, 40.50856], [72.38384, 40.51535], [72.41714, 40.55736], [72.34406, 40.60144], [72.40517, 40.61917], [72.47795, 40.5532], [72.66713, 40.5219], [72.66713, 40.59076], [72.69579, 40.59778], [72.73995, 40.58409], [72.74768, 40.58051], [72.74862, 40.57131], [72.75982, 40.57273], [72.74894, 40.59592], [72.74866, 40.60873], [72.80137, 40.67856], [72.84754, 40.67229], [72.85372, 40.7116], [72.8722, 40.71111], [72.93296, 40.73089], [72.99133, 40.76457], [73.0612, 40.76678], [73.13412, 40.79122], [73.13267, 40.83512], [73.01869, 40.84681], [72.94454, 40.8094], [72.84291, 40.85512], [72.68157, 40.84942], [72.59136, 40.86947], [72.55109, 40.96046], [72.48742, 40.97136], [72.45206, 41.03018], [72.38511, 41.02785], [72.36138, 41.04384], [72.34757, 41.06104], [72.34026, 41.04539], [72.324, 41.03381], [72.18339, 40.99571], [72.17594, 41.02377], [72.21061, 41.05607], [72.1792, 41.10621], [72.14864, 41.13363], [72.17594, 41.15522], [72.16433, 41.16483], [72.10745, 41.15483], [72.07249, 41.11739], [71.85964, 41.19081], [71.91457, 41.2982], [71.83914, 41.3546], [71.76625, 41.4466], [71.71132, 41.43012], [71.73054, 41.54713], [71.65914, 41.49599], [71.6787, 41.42111], [71.57227, 41.29175], [71.46688, 41.31883], [71.43814, 41.19644], [71.46148, 41.13958], [71.40198, 41.09436], [71.34877, 41.16807], [71.27187, 41.11015], [71.25813, 41.18796], [71.11806, 41.15359], [71.02193, 41.19494], [70.9615, 41.16393], [70.86263, 41.23833], [70.77885, 41.24813], [70.78572, 41.36419], [70.67586, 41.47953], [70.48909, 41.40335], [70.17682, 41.5455], [70.69777, 41.92554], [71.28719, 42.18033], [71.13263, 42.28356], [70.94483, 42.26238], [69.49545, 41.545], [69.45751, 41.56863], [69.39485, 41.51518], [69.45081, 41.46246], [69.37468, 41.46555], [69.35554, 41.47211], [69.29778, 41.43673], [69.25059, 41.46693], [69.23332, 41.45847], [69.22671, 41.46298], [69.20439, 41.45391], [69.18528, 41.45175], [69.17701, 41.43769], [69.15137, 41.43078], [69.05006, 41.36183], [69.01308, 41.22804], [68.7217, 41.05025], [68.73945, 40.96989], [68.65662, 40.93861], [68.62221, 41.03019], [68.49983, 40.99669], [68.58444, 40.91447], [68.63, 40.59358], [68.49983, 40.56437], [67.96736, 40.83798], [68.1271, 41.0324], [68.08273, 41.08148], [67.98511, 41.02794], [67.9644, 41.14611], [66.69129, 41.1311], [66.53302, 41.87388], [66.00546, 41.94455], [66.09482, 42.93426], [65.85194, 42.85481]], [[70.68112, 40.90612], [70.6721, 40.90555], [70.57501, 40.98941], [70.54223, 40.98787], [70.56077, 41.00642], [70.6158, 40.97661], [70.68112, 40.90612]]], [[[71.21139, 40.03369], [71.12218, 40.03052], [71.06305, 40.1771], [71.00236, 40.18154], [71.01035, 40.05481], [71.11037, 40.01984], [71.11668, 39.99291], [71.09063, 39.99], [71.10501, 39.95568], [71.04979, 39.89808], [71.10531, 39.91354], [71.16101, 39.88423], [71.23067, 39.93581], [71.1427, 39.95026], [71.21139, 40.03369]]], [[[71.86463, 39.98598], [71.78838, 40.01404], [71.71511, 39.96348], [71.7504, 39.93701], [71.84316, 39.95582], [71.86463, 39.98598]]]]
26666           }
26667         }, {
26668           type: "Feature",
26669           properties: {
26670             iso1A2: "VA",
26671             iso1A3: "VAT",
26672             iso1N3: "336",
26673             wikidata: "Q237",
26674             nameEn: "Vatican City",
26675             aliases: ["Holy See"],
26676             groups: ["039", "150"],
26677             callingCodes: ["379", "39 06"]
26678           },
26679           geometry: {
26680             type: "MultiPolygon",
26681             coordinates: [[[[12.45181, 41.90056], [12.45446, 41.90028], [12.45435, 41.90143], [12.45626, 41.90172], [12.45691, 41.90125], [12.4577, 41.90115], [12.45834, 41.90174], [12.45826, 41.90281], [12.45755, 41.9033], [12.45762, 41.9058], [12.45561, 41.90629], [12.45543, 41.90738], [12.45091, 41.90625], [12.44984, 41.90545], [12.44815, 41.90326], [12.44582, 41.90194], [12.44834, 41.90095], [12.45181, 41.90056]]]]
26682           }
26683         }, {
26684           type: "Feature",
26685           properties: {
26686             iso1A2: "VC",
26687             iso1A3: "VCT",
26688             iso1N3: "670",
26689             wikidata: "Q757",
26690             nameEn: "St. Vincent and the Grenadines",
26691             aliases: ["WV"],
26692             groups: ["029", "003", "419", "019", "UN"],
26693             driveSide: "left",
26694             roadSpeedUnit: "mph",
26695             callingCodes: ["1 784"]
26696           },
26697           geometry: {
26698             type: "MultiPolygon",
26699             coordinates: [[[[-62.64026, 12.69984], [-59.94058, 12.34011], [-61.69315, 14.26451], [-62.64026, 12.69984]]]]
26700           }
26701         }, {
26702           type: "Feature",
26703           properties: {
26704             iso1A2: "VE",
26705             iso1A3: "VEN",
26706             iso1N3: "862",
26707             wikidata: "Q717",
26708             nameEn: "Venezuela",
26709             aliases: ["YV"],
26710             groups: ["005", "419", "019", "UN"],
26711             callingCodes: ["58"]
26712           },
26713           geometry: {
26714             type: "MultiPolygon",
26715             coordinates: [[[[-71.22331, 13.01387], [-70.92579, 11.96275], [-71.3275, 11.85], [-71.9675, 11.65536], [-72.24983, 11.14138], [-72.4767, 11.1117], [-72.88002, 10.44309], [-72.98085, 9.85253], [-73.36905, 9.16636], [-73.02119, 9.27584], [-72.94052, 9.10663], [-72.77415, 9.10165], [-72.65474, 8.61428], [-72.4042, 8.36513], [-72.36987, 8.19976], [-72.35163, 8.01163], [-72.39137, 8.03534], [-72.47213, 7.96106], [-72.48801, 7.94329], [-72.48183, 7.92909], [-72.47042, 7.92306], [-72.45806, 7.91141], [-72.46183, 7.90682], [-72.44454, 7.86031], [-72.46763, 7.79518], [-72.47827, 7.65604], [-72.45321, 7.57232], [-72.47415, 7.48928], [-72.43132, 7.40034], [-72.19437, 7.37034], [-72.04895, 7.03837], [-71.82441, 7.04314], [-71.44118, 7.02116], [-71.42212, 7.03854], [-71.37234, 7.01588], [-71.03941, 6.98163], [-70.7596, 7.09799], [-70.10716, 6.96516], [-69.41843, 6.1072], [-67.60654, 6.2891], [-67.4625, 6.20625], [-67.43513, 5.98835], [-67.58558, 5.84537], [-67.63914, 5.64963], [-67.59141, 5.5369], [-67.83341, 5.31104], [-67.85358, 4.53249], [-67.62671, 3.74303], [-67.50067, 3.75812], [-67.30945, 3.38393], [-67.85862, 2.86727], [-67.85862, 2.79173], [-67.65696, 2.81691], [-67.21967, 2.35778], [-66.85795, 1.22998], [-66.28507, 0.74585], [-65.6727, 1.01353], [-65.50158, 0.92086], [-65.57288, 0.62856], [-65.11657, 1.12046], [-64.38932, 1.5125], [-64.34654, 1.35569], [-64.08274, 1.64792], [-64.06135, 1.94722], [-63.39827, 2.16098], [-63.39114, 2.4317], [-64.0257, 2.48156], [-64.02908, 2.79797], [-64.48379, 3.7879], [-64.84028, 4.24665], [-64.72977, 4.28931], [-64.57648, 4.12576], [-64.14512, 4.12932], [-63.99183, 3.90172], [-63.86082, 3.94796], [-63.70218, 3.91417], [-63.67099, 4.01731], [-63.50611, 3.83592], [-63.42233, 3.89995], [-63.4464, 3.9693], [-63.21111, 3.96219], [-62.98296, 3.59935], [-62.7655, 3.73099], [-62.74411, 4.03331], [-62.57656, 4.04754], [-62.44822, 4.18621], [-62.13094, 4.08309], [-61.54629, 4.2822], [-61.48569, 4.43149], [-61.29675, 4.44216], [-61.31457, 4.54167], [-61.15703, 4.49839], [-60.98303, 4.54167], [-60.86539, 4.70512], [-60.5802, 4.94312], [-60.73204, 5.20931], [-61.4041, 5.95304], [-61.15058, 6.19558], [-61.20762, 6.58174], [-61.13632, 6.70922], [-60.54873, 6.8631], [-60.39419, 6.94847], [-60.28074, 7.1162], [-60.44116, 7.20817], [-60.54098, 7.14804], [-60.63367, 7.25061], [-60.59802, 7.33194], [-60.71923, 7.55817], [-60.64793, 7.56877], [-60.51959, 7.83373], [-60.38056, 7.8302], [-60.02407, 8.04557], [-59.97059, 8.20791], [-59.83156, 8.23261], [-59.80661, 8.28906], [-59.85562, 8.35213], [-59.98508, 8.53046], [-59.54058, 8.6862], [-60.89962, 9.81445], [-62.08693, 10.04435], [-61.62505, 11.18974], [-63.73917, 11.92623], [-63.19938, 16.44103], [-67.89186, 12.4116], [-68.01417, 11.77722], [-68.33524, 11.78151], [-68.99639, 11.79035], [-71.22331, 13.01387]]]]
26716           }
26717         }, {
26718           type: "Feature",
26719           properties: {
26720             iso1A2: "VG",
26721             iso1A3: "VGB",
26722             iso1N3: "092",
26723             wikidata: "Q25305",
26724             nameEn: "British Virgin Islands",
26725             country: "GB",
26726             groups: ["BOTS", "029", "003", "419", "019", "UN"],
26727             driveSide: "left",
26728             roadSpeedUnit: "mph",
26729             roadHeightUnit: "ft",
26730             callingCodes: ["1 284"]
26731           },
26732           geometry: {
26733             type: "MultiPolygon",
26734             coordinates: [[[[-64.47127, 17.55688], [-63.88746, 19.15706], [-65.02435, 18.73231], [-64.86027, 18.39056], [-64.64673, 18.36549], [-64.47127, 17.55688]]]]
26735           }
26736         }, {
26737           type: "Feature",
26738           properties: {
26739             iso1A2: "VI",
26740             iso1A3: "VIR",
26741             iso1N3: "850",
26742             wikidata: "Q11703",
26743             nameEn: "United States Virgin Islands",
26744             aliases: ["US-VI"],
26745             country: "US",
26746             groups: ["Q1352230", "029", "003", "419", "019", "UN"],
26747             driveSide: "left",
26748             roadSpeedUnit: "mph",
26749             roadHeightUnit: "ft",
26750             callingCodes: ["1 340"]
26751           },
26752           geometry: {
26753             type: "MultiPolygon",
26754             coordinates: [[[[-65.02435, 18.73231], [-65.27974, 17.56928], [-64.47127, 17.55688], [-64.64673, 18.36549], [-64.86027, 18.39056], [-65.02435, 18.73231]]]]
26755           }
26756         }, {
26757           type: "Feature",
26758           properties: {
26759             iso1A2: "VN",
26760             iso1A3: "VNM",
26761             iso1N3: "704",
26762             wikidata: "Q881",
26763             nameEn: "Vietnam",
26764             groups: ["035", "142", "UN"],
26765             callingCodes: ["84"]
26766           },
26767           geometry: {
26768             type: "MultiPolygon",
26769             coordinates: [[[[108.10003, 21.47338], [108.0569, 21.53604], [108.02926, 21.54997], [107.97932, 21.54503], [107.97383, 21.53961], [107.97074, 21.54072], [107.96774, 21.53601], [107.95232, 21.5388], [107.92652, 21.58906], [107.90006, 21.5905], [107.86114, 21.65128], [107.80355, 21.66141], [107.66967, 21.60787], [107.56537, 21.61945], [107.54047, 21.5934], [107.49065, 21.59774], [107.49532, 21.62958], [107.47197, 21.6672], [107.41593, 21.64839], [107.38636, 21.59774], [107.35989, 21.60063], [107.35834, 21.6672], [107.29296, 21.74674], [107.24625, 21.7077], [107.20734, 21.71493], [107.10771, 21.79879], [107.02615, 21.81981], [107.00964, 21.85948], [107.06101, 21.88982], [107.05634, 21.92303], [106.99252, 21.95191], [106.97228, 21.92592], [106.92714, 21.93459], [106.9178, 21.97357], [106.81038, 21.97934], [106.74345, 22.00965], [106.72551, 21.97923], [106.69276, 21.96013], [106.68274, 21.99811], [106.70142, 22.02409], [106.6983, 22.15102], [106.67495, 22.1885], [106.69986, 22.22309], [106.6516, 22.33977], [106.55976, 22.34841], [106.57221, 22.37], [106.55665, 22.46498], [106.58395, 22.474], [106.61269, 22.60301], [106.65316, 22.5757], [106.71698, 22.58432], [106.72321, 22.63606], [106.76293, 22.73491], [106.82404, 22.7881], [106.83685, 22.8098], [106.81271, 22.8226], [106.78422, 22.81532], [106.71128, 22.85982], [106.71387, 22.88296], [106.6734, 22.89587], [106.6516, 22.86862], [106.60179, 22.92884], [106.55976, 22.92311], [106.51306, 22.94891], [106.49749, 22.91164], [106.34961, 22.86718], [106.27022, 22.87722], [106.19705, 22.98475], [106.00179, 22.99049], [105.99568, 22.94178], [105.90119, 22.94168], [105.8726, 22.92756], [105.72382, 23.06641], [105.57594, 23.075], [105.56037, 23.16806], [105.49966, 23.20669], [105.42805, 23.30824], [105.40782, 23.28107], [105.32376, 23.39684], [105.22569, 23.27249], [105.17276, 23.28679], [105.11672, 23.25247], [105.07002, 23.26248], [104.98712, 23.19176], [104.96532, 23.20463], [104.9486, 23.17235], [104.91435, 23.18666], [104.87992, 23.17141], [104.87382, 23.12854], [104.79478, 23.12934], [104.8334, 23.01484], [104.86765, 22.95178], [104.84942, 22.93631], [104.77114, 22.90017], [104.72755, 22.81984], [104.65283, 22.83419], [104.60457, 22.81841], [104.58122, 22.85571], [104.47225, 22.75813], [104.35593, 22.69353], [104.25683, 22.76534], [104.27084, 22.8457], [104.11384, 22.80363], [104.03734, 22.72945], [104.01088, 22.51823], [103.99247, 22.51958], [103.97384, 22.50634], [103.96783, 22.51173], [103.96352, 22.50584], [103.95191, 22.5134], [103.94513, 22.52553], [103.93286, 22.52703], [103.87904, 22.56683], [103.64506, 22.79979], [103.56255, 22.69499], [103.57812, 22.65764], [103.52675, 22.59155], [103.43646, 22.70648], [103.43179, 22.75816], [103.32282, 22.8127], [103.28079, 22.68063], [103.18895, 22.64471], [103.15782, 22.59873], [103.17961, 22.55705], [103.07843, 22.50097], [103.0722, 22.44775], [102.9321, 22.48659], [102.8636, 22.60735], [102.60675, 22.73376], [102.57095, 22.7036], [102.51802, 22.77969], [102.46665, 22.77108], [102.42618, 22.69212], [102.38415, 22.67919], [102.41061, 22.64184], [102.25339, 22.4607], [102.26428, 22.41321], [102.16621, 22.43336], [102.14099, 22.40092], [102.18712, 22.30403], [102.51734, 22.02676], [102.49092, 21.99002], [102.62301, 21.91447], [102.67145, 21.65894], [102.74189, 21.66713], [102.82115, 21.73667], [102.81894, 21.83888], [102.85637, 21.84501], [102.86077, 21.71213], [102.97965, 21.74076], [102.98846, 21.58936], [102.86297, 21.4255], [102.94223, 21.46034], [102.88939, 21.3107], [102.80794, 21.25736], [102.89825, 21.24707], [102.97745, 21.05821], [103.03469, 21.05821], [103.12055, 20.89994], [103.21497, 20.89832], [103.38032, 20.79501], [103.45737, 20.82382], [103.68633, 20.66324], [103.73478, 20.6669], [103.82282, 20.8732], [103.98024, 20.91531], [104.11121, 20.96779], [104.27412, 20.91433], [104.63957, 20.6653], [104.38199, 20.47155], [104.40621, 20.3849], [104.47886, 20.37459], [104.66158, 20.47774], [104.72102, 20.40554], [104.62195, 20.36633], [104.61315, 20.24452], [104.86852, 20.14121], [104.91695, 20.15567], [104.9874, 20.09573], [104.8465, 19.91783], [104.8355, 19.80395], [104.68359, 19.72729], [104.64837, 19.62365], [104.53169, 19.61743], [104.41281, 19.70035], [104.23229, 19.70242], [104.06498, 19.66926], [104.05617, 19.61743], [104.10832, 19.51575], [104.06058, 19.43484], [103.87125, 19.31854], [104.5361, 18.97747], [104.64617, 18.85668], [105.12829, 18.70453], [105.19654, 18.64196], [105.1327, 18.58355], [105.10408, 18.43533], [105.15942, 18.38691], [105.38366, 18.15315], [105.46292, 18.22008], [105.64784, 17.96687], [105.60381, 17.89356], [105.76612, 17.67147], [105.85744, 17.63221], [106.09019, 17.36399], [106.18991, 17.28227], [106.24444, 17.24714], [106.29287, 17.3018], [106.31929, 17.20509], [106.43597, 17.01362], [106.50862, 16.9673], [106.55045, 17.0031], [106.54824, 16.92729], [106.51963, 16.92097], [106.52183, 16.87884], [106.55265, 16.86831], [106.55485, 16.68704], [106.59013, 16.62259], [106.58267, 16.6012], [106.61477, 16.60713], [106.66052, 16.56892], [106.65832, 16.47816], [106.74418, 16.41904], [106.84104, 16.55415], [106.88727, 16.52671], [106.88067, 16.43594], [106.96638, 16.34938], [106.97385, 16.30204], [107.02597, 16.31132], [107.09091, 16.3092], [107.15035, 16.26271], [107.14595, 16.17816], [107.25822, 16.13587], [107.33968, 16.05549], [107.44975, 16.08511], [107.46296, 16.01106], [107.39471, 15.88829], [107.34188, 15.89464], [107.21419, 15.83747], [107.21859, 15.74638], [107.27143, 15.71459], [107.27583, 15.62769], [107.34408, 15.62345], [107.3815, 15.49832], [107.50699, 15.48771], [107.53341, 15.40496], [107.62367, 15.42193], [107.60605, 15.37524], [107.62587, 15.2266], [107.58844, 15.20111], [107.61926, 15.13949], [107.61486, 15.0566], [107.46516, 15.00982], [107.48277, 14.93751], [107.59285, 14.87795], [107.51579, 14.79282], [107.54361, 14.69092], [107.55371, 14.628], [107.52102, 14.59034], [107.52569, 14.54665], [107.48521, 14.40346], [107.44941, 14.41552], [107.39493, 14.32655], [107.40427, 14.24509], [107.33577, 14.11832], [107.37158, 14.07906], [107.35757, 14.02319], [107.38247, 13.99147], [107.44318, 13.99751], [107.46498, 13.91593], [107.45252, 13.78897], [107.53503, 13.73908], [107.61909, 13.52577], [107.62843, 13.3668], [107.49144, 13.01215], [107.49611, 12.88926], [107.55993, 12.7982], [107.5755, 12.52177], [107.55059, 12.36824], [107.4463, 12.29373], [107.42917, 12.24657], [107.34511, 12.33327], [107.15831, 12.27547], [106.99953, 12.08983], [106.92325, 12.06548], [106.79405, 12.0807], [106.70687, 11.96956], [106.4111, 11.97413], [106.4687, 11.86751], [106.44068, 11.86294], [106.44535, 11.8279], [106.41577, 11.76999], [106.45158, 11.68616], [106.44691, 11.66787], [106.37219, 11.69836], [106.30525, 11.67549], [106.26478, 11.72122], [106.18539, 11.75171], [106.13158, 11.73283], [106.06708, 11.77761], [106.02038, 11.77457], [106.00792, 11.7197], [105.95188, 11.63738], [105.88962, 11.67854], [105.8507, 11.66635], [105.80867, 11.60536], [105.81645, 11.56876], [105.87328, 11.55953], [105.88962, 11.43605], [105.86782, 11.28343], [106.10444, 11.07879], [106.1527, 11.10476], [106.1757, 11.07301], [106.20095, 10.97795], [106.14301, 10.98176], [106.18539, 10.79451], [106.06708, 10.8098], [105.94535, 10.9168], [105.93403, 10.83853], [105.84603, 10.85873], [105.86376, 10.89839], [105.77751, 11.03671], [105.50045, 10.94586], [105.42884, 10.96878], [105.34011, 10.86179], [105.11449, 10.96332], [105.08326, 10.95656], [105.02722, 10.89236], [105.09571, 10.72722], [104.95094, 10.64003], [104.87933, 10.52833], [104.59018, 10.53073], [104.49869, 10.4057], [104.47963, 10.43046], [104.43778, 10.42386], [103.99198, 10.48391], [102.47649, 9.66162], [104.81582, 8.03101], [109.55486, 8.10026], [111.60491, 13.57105], [108.00365, 17.98159], [108.10003, 21.47338]]]]
26770           }
26771         }, {
26772           type: "Feature",
26773           properties: {
26774             iso1A2: "VU",
26775             iso1A3: "VUT",
26776             iso1N3: "548",
26777             wikidata: "Q686",
26778             nameEn: "Vanuatu",
26779             groups: ["054", "009", "UN"],
26780             callingCodes: ["678"]
26781           },
26782           geometry: {
26783             type: "MultiPolygon",
26784             coordinates: [[[[156.73836, -14.50464], [174.245, -23.1974], [172.71443, -12.01327], [156.73836, -14.50464]]]]
26785           }
26786         }, {
26787           type: "Feature",
26788           properties: {
26789             iso1A2: "WF",
26790             iso1A3: "WLF",
26791             iso1N3: "876",
26792             wikidata: "Q35555",
26793             nameEn: "Wallis and Futuna",
26794             country: "FR",
26795             groups: ["Q1451600", "061", "009", "UN"],
26796             callingCodes: ["681"]
26797           },
26798           geometry: {
26799             type: "MultiPolygon",
26800             coordinates: [[[[-178.66551, -14.32452], [-176.76826, -14.95183], [-175.59809, -12.61507], [-178.66551, -14.32452]]]]
26801           }
26802         }, {
26803           type: "Feature",
26804           properties: {
26805             iso1A2: "WS",
26806             iso1A3: "WSM",
26807             iso1N3: "882",
26808             wikidata: "Q683",
26809             nameEn: "Samoa",
26810             groups: ["061", "009", "UN"],
26811             driveSide: "left",
26812             callingCodes: ["685"]
26813           },
26814           geometry: {
26815             type: "MultiPolygon",
26816             coordinates: [[[[-173.74402, -14.26669], [-170.99605, -15.1275], [-171.39864, -10.21587], [-173.74402, -14.26669]]]]
26817           }
26818         }, {
26819           type: "Feature",
26820           properties: {
26821             iso1A2: "XK",
26822             iso1A3: "XKX",
26823             wikidata: "Q1246",
26824             nameEn: "Kosovo",
26825             aliases: ["KV"],
26826             groups: ["039", "150"],
26827             isoStatus: "usrAssn",
26828             callingCodes: ["383"]
26829           },
26830           geometry: {
26831             type: "MultiPolygon",
26832             coordinates: [[[[21.39045, 42.74888], [21.44047, 42.87276], [21.36941, 42.87397], [21.32974, 42.90424], [21.2719, 42.8994], [21.23534, 42.95523], [21.23877, 43.00848], [21.2041, 43.02277], [21.16734, 42.99694], [21.14465, 43.11089], [21.08952, 43.13471], [21.05378, 43.10707], [21.00749, 43.13984], [20.96287, 43.12416], [20.83727, 43.17842], [20.88685, 43.21697], [20.82145, 43.26769], [20.73811, 43.25068], [20.68688, 43.21335], [20.59929, 43.20492], [20.69515, 43.09641], [20.64557, 43.00826], [20.59929, 43.01067], [20.48692, 42.93208], [20.53484, 42.8885], [20.43734, 42.83157], [20.40594, 42.84853], [20.35692, 42.8335], [20.27869, 42.81945], [20.2539, 42.76245], [20.04898, 42.77701], [20.02088, 42.74789], [20.02915, 42.71147], [20.0969, 42.65559], [20.07761, 42.55582], [20.17127, 42.50469], [20.21797, 42.41237], [20.24399, 42.32168], [20.34479, 42.32656], [20.3819, 42.3029], [20.48857, 42.25444], [20.56955, 42.12097], [20.55633, 42.08173], [20.59434, 42.03879], [20.63069, 41.94913], [20.57946, 41.91593], [20.59524, 41.8818], [20.68523, 41.85318], [20.76786, 41.91839], [20.75464, 42.05229], [21.11491, 42.20794], [21.16614, 42.19815], [21.22728, 42.08909], [21.31983, 42.10993], [21.29913, 42.13954], [21.30496, 42.1418], [21.38428, 42.24465], [21.43882, 42.23609], [21.43882, 42.2789], [21.50823, 42.27156], [21.52145, 42.24465], [21.58992, 42.25915], [21.56772, 42.30946], [21.5264, 42.33634], [21.53467, 42.36809], [21.57021, 42.3647], [21.59029, 42.38042], [21.62887, 42.37664], [21.64209, 42.41081], [21.62556, 42.45106], [21.7035, 42.51899], [21.70522, 42.54176], [21.7327, 42.55041], [21.75672, 42.62695], [21.79413, 42.65923], [21.75025, 42.70125], [21.6626, 42.67813], [21.58755, 42.70418], [21.59154, 42.72643], [21.47498, 42.74695], [21.39045, 42.74888]]]]
26833           }
26834         }, {
26835           type: "Feature",
26836           properties: {
26837             iso1A2: "YE",
26838             iso1A3: "YEM",
26839             iso1N3: "887",
26840             wikidata: "Q805",
26841             nameEn: "Yemen",
26842             groups: ["145", "142", "UN"],
26843             callingCodes: ["967"]
26844           },
26845           geometry: {
26846             type: "MultiPolygon",
26847             coordinates: [[[[57.49095, 8.14549], [52.81185, 17.28568], [52.74267, 17.29519], [52.78009, 17.35124], [52.00311, 19.00083], [49.04884, 18.59899], [48.19996, 18.20584], [47.58351, 17.50366], [47.48245, 17.10808], [47.00571, 16.94765], [46.76494, 17.29151], [46.31018, 17.20464], [44.50126, 17.47475], [43.70631, 17.35762], [43.43005, 17.56148], [43.29185, 17.53224], [43.22533, 17.38343], [43.32653, 17.31179], [43.20156, 17.25901], [43.17787, 17.14717], [43.23967, 17.03428], [43.18233, 17.02673], [43.1813, 16.98438], [43.19328, 16.94703], [43.1398, 16.90696], [43.18338, 16.84852], [43.22012, 16.83932], [43.22956, 16.80613], [43.24801, 16.80613], [43.26303, 16.79479], [43.25857, 16.75304], [43.21325, 16.74416], [43.22066, 16.65179], [43.15274, 16.67248], [43.11601, 16.53166], [42.97215, 16.51093], [42.94351, 16.49467], [42.94625, 16.39721], [42.76801, 16.40371], [42.15205, 16.40211], [40.99158, 15.81743], [43.29075, 12.79154], [43.32909, 12.59711], [43.90659, 12.3823], [51.12877, 12.56479], [57.49095, 8.14549]]]]
26848           }
26849         }, {
26850           type: "Feature",
26851           properties: {
26852             iso1A2: "YT",
26853             iso1A3: "MYT",
26854             iso1N3: "175",
26855             wikidata: "Q17063",
26856             nameEn: "Mayotte",
26857             country: "FR",
26858             groups: ["Q3320166", "EU", "014", "202", "002", "UN"],
26859             callingCodes: ["262"]
26860           },
26861           geometry: {
26862             type: "MultiPolygon",
26863             coordinates: [[[[43.28731, -13.97126], [45.54824, -13.22353], [45.4971, -11.75965], [43.28731, -13.97126]]]]
26864           }
26865         }, {
26866           type: "Feature",
26867           properties: {
26868             iso1A2: "ZA",
26869             iso1A3: "ZAF",
26870             iso1N3: "710",
26871             wikidata: "Q258",
26872             nameEn: "South Africa",
26873             groups: ["018", "202", "002", "UN"],
26874             driveSide: "left",
26875             callingCodes: ["27"]
26876           },
26877           geometry: {
26878             type: "MultiPolygon",
26879             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]]]]
26880           }
26881         }, {
26882           type: "Feature",
26883           properties: {
26884             iso1A2: "ZM",
26885             iso1A3: "ZMB",
26886             iso1N3: "894",
26887             wikidata: "Q953",
26888             nameEn: "Zambia",
26889             groups: ["014", "202", "002", "UN"],
26890             driveSide: "left",
26891             callingCodes: ["260"]
26892           },
26893           geometry: {
26894             type: "MultiPolygon",
26895             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]]]]
26896           }
26897         }, {
26898           type: "Feature",
26899           properties: {
26900             iso1A2: "ZW",
26901             iso1A3: "ZWE",
26902             iso1N3: "716",
26903             wikidata: "Q954",
26904             nameEn: "Zimbabwe",
26905             groups: ["014", "202", "002", "UN"],
26906             driveSide: "left",
26907             callingCodes: ["263"]
26908           },
26909           geometry: {
26910             type: "MultiPolygon",
26911             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]]]]
26912           }
26913         }];
26914         var borders_default = {
26915           type: type,
26916           features: features
26917         }; // src/country-coder.ts
26918
26919         var borders = borders_default;
26920         var whichPolygonGetter = {};
26921         var featuresByCode = {};
26922         var idFilterRegex = /(?=(?!^(and|the|of|el|la|de)$))(\b(and|the|of|el|la|de)\b)|[-_ .,'()&[\]/]/gi;
26923
26924         function canonicalID(id) {
26925           var s = id || "";
26926
26927           if (s.charAt(0) === ".") {
26928             return s.toUpperCase();
26929           } else {
26930             return s.replace(idFilterRegex, "").toUpperCase();
26931           }
26932         }
26933
26934         var levels = ["subterritory", "territory", "subcountryGroup", "country", "sharedLandform", "intermediateRegion", "subregion", "region", "subunion", "union", "unitedNations", "world"];
26935         loadDerivedDataAndCaches(borders);
26936
26937         function loadDerivedDataAndCaches(borders2) {
26938           var identifierProps = ["iso1A2", "iso1A3", "m49", "wikidata", "emojiFlag", "ccTLD", "nameEn"];
26939           var geometryFeatures = [];
26940
26941           for (var i in borders2.features) {
26942             var feature2 = borders2.features[i];
26943             feature2.properties.id = feature2.properties.iso1A2 || feature2.properties.m49 || feature2.properties.wikidata;
26944             loadM49(feature2);
26945             loadTLD(feature2);
26946             loadIsoStatus(feature2);
26947             loadLevel(feature2);
26948             loadGroups(feature2);
26949             loadFlag(feature2);
26950             cacheFeatureByIDs(feature2);
26951             if (feature2.geometry) geometryFeatures.push(feature2);
26952           }
26953
26954           for (var _i in borders2.features) {
26955             var _feature = borders2.features[_i];
26956             _feature.properties.groups = _feature.properties.groups.map(function (groupID) {
26957               return featuresByCode[groupID].properties.id;
26958             });
26959             loadMembersForGroupsOf(_feature);
26960           }
26961
26962           for (var _i2 in borders2.features) {
26963             var _feature2 = borders2.features[_i2];
26964             loadRoadSpeedUnit(_feature2);
26965             loadRoadHeightUnit(_feature2);
26966             loadDriveSide(_feature2);
26967             loadCallingCodes(_feature2);
26968             loadGroupGroups(_feature2);
26969           }
26970
26971           for (var _i3 in borders2.features) {
26972             var _feature3 = borders2.features[_i3];
26973
26974             _feature3.properties.groups.sort(function (groupID1, groupID2) {
26975               return levels.indexOf(featuresByCode[groupID1].properties.level) - levels.indexOf(featuresByCode[groupID2].properties.level);
26976             });
26977
26978             if (_feature3.properties.members) _feature3.properties.members.sort(function (id1, id2) {
26979               var diff = levels.indexOf(featuresByCode[id1].properties.level) - levels.indexOf(featuresByCode[id2].properties.level);
26980
26981               if (diff === 0) {
26982                 return borders2.features.indexOf(featuresByCode[id1]) - borders2.features.indexOf(featuresByCode[id2]);
26983               }
26984
26985               return diff;
26986             });
26987           }
26988
26989           var geometryOnlyCollection = {
26990             type: "FeatureCollection",
26991             features: geometryFeatures
26992           };
26993           whichPolygonGetter = whichPolygon_1(geometryOnlyCollection);
26994
26995           function loadGroups(feature2) {
26996             var props = feature2.properties;
26997
26998             if (!props.groups) {
26999               props.groups = [];
27000             }
27001
27002             if (feature2.geometry && props.country) {
27003               props.groups.push(props.country);
27004             }
27005
27006             if (props.m49 !== "001") {
27007               props.groups.push("001");
27008             }
27009           }
27010
27011           function loadM49(feature2) {
27012             var props = feature2.properties;
27013
27014             if (!props.m49 && props.iso1N3) {
27015               props.m49 = props.iso1N3;
27016             }
27017           }
27018
27019           function loadTLD(feature2) {
27020             var props = feature2.properties;
27021             if (props.level === "unitedNations") return;
27022
27023             if (!props.ccTLD && props.iso1A2) {
27024               props.ccTLD = "." + props.iso1A2.toLowerCase();
27025             }
27026           }
27027
27028           function loadIsoStatus(feature2) {
27029             var props = feature2.properties;
27030
27031             if (!props.isoStatus && props.iso1A2) {
27032               props.isoStatus = "official";
27033             }
27034           }
27035
27036           function loadLevel(feature2) {
27037             var props = feature2.properties;
27038             if (props.level) return;
27039
27040             if (!props.country) {
27041               props.level = "country";
27042             } else if (!props.iso1A2 || props.isoStatus === "official") {
27043               props.level = "territory";
27044             } else {
27045               props.level = "subterritory";
27046             }
27047           }
27048
27049           function loadGroupGroups(feature2) {
27050             var props = feature2.properties;
27051             if (feature2.geometry || !props.members) return;
27052             var featureLevelIndex = levels.indexOf(props.level);
27053             var sharedGroups = [];
27054
27055             var _loop = function _loop(_i4) {
27056               var memberID = props.members[_i4];
27057               var member = featuresByCode[memberID];
27058               var memberGroups = member.properties.groups.filter(function (groupID) {
27059                 return groupID !== feature2.properties.id && featureLevelIndex < levels.indexOf(featuresByCode[groupID].properties.level);
27060               });
27061
27062               if (_i4 === "0") {
27063                 sharedGroups = memberGroups;
27064               } else {
27065                 sharedGroups = sharedGroups.filter(function (groupID) {
27066                   return memberGroups.indexOf(groupID) !== -1;
27067                 });
27068               }
27069             };
27070
27071             for (var _i4 in props.members) {
27072               _loop(_i4);
27073             }
27074
27075             props.groups = props.groups.concat(sharedGroups.filter(function (groupID) {
27076               return props.groups.indexOf(groupID) === -1;
27077             }));
27078
27079             for (var j in sharedGroups) {
27080               var groupFeature = featuresByCode[sharedGroups[j]];
27081
27082               if (groupFeature.properties.members.indexOf(props.id) === -1) {
27083                 groupFeature.properties.members.push(props.id);
27084               }
27085             }
27086           }
27087
27088           function loadRoadSpeedUnit(feature2) {
27089             var props = feature2.properties;
27090
27091             if (feature2.geometry) {
27092               if (!props.roadSpeedUnit) props.roadSpeedUnit = "km/h";
27093             } else if (props.members) {
27094               var vals = Array.from(new Set(props.members.map(function (id) {
27095                 var member = featuresByCode[id];
27096                 if (member.geometry) return member.properties.roadSpeedUnit || "km/h";
27097               }).filter(Boolean)));
27098               if (vals.length === 1) props.roadSpeedUnit = vals[0];
27099             }
27100           }
27101
27102           function loadRoadHeightUnit(feature2) {
27103             var props = feature2.properties;
27104
27105             if (feature2.geometry) {
27106               if (!props.roadHeightUnit) props.roadHeightUnit = "m";
27107             } else if (props.members) {
27108               var vals = Array.from(new Set(props.members.map(function (id) {
27109                 var member = featuresByCode[id];
27110                 if (member.geometry) return member.properties.roadHeightUnit || "m";
27111               }).filter(Boolean)));
27112               if (vals.length === 1) props.roadHeightUnit = vals[0];
27113             }
27114           }
27115
27116           function loadDriveSide(feature2) {
27117             var props = feature2.properties;
27118
27119             if (feature2.geometry) {
27120               if (!props.driveSide) props.driveSide = "right";
27121             } else if (props.members) {
27122               var vals = Array.from(new Set(props.members.map(function (id) {
27123                 var member = featuresByCode[id];
27124                 if (member.geometry) return member.properties.driveSide || "right";
27125               }).filter(Boolean)));
27126               if (vals.length === 1) props.driveSide = vals[0];
27127             }
27128           }
27129
27130           function loadCallingCodes(feature2) {
27131             var props = feature2.properties;
27132
27133             if (!feature2.geometry && props.members) {
27134               props.callingCodes = Array.from(new Set(props.members.reduce(function (array, id) {
27135                 var member = featuresByCode[id];
27136                 if (member.geometry && member.properties.callingCodes) return array.concat(member.properties.callingCodes);
27137                 return array;
27138               }, [])));
27139             }
27140           }
27141
27142           function loadFlag(feature2) {
27143             if (!feature2.properties.iso1A2) return;
27144             var flag = feature2.properties.iso1A2.replace(/./g, function (_char) {
27145               return String.fromCodePoint(_char.charCodeAt(0) + 127397);
27146             });
27147             feature2.properties.emojiFlag = flag;
27148           }
27149
27150           function loadMembersForGroupsOf(feature2) {
27151             for (var j in feature2.properties.groups) {
27152               var groupID = feature2.properties.groups[j];
27153               var groupFeature = featuresByCode[groupID];
27154               if (!groupFeature.properties.members) groupFeature.properties.members = [];
27155               groupFeature.properties.members.push(feature2.properties.id);
27156             }
27157           }
27158
27159           function cacheFeatureByIDs(feature2) {
27160             var ids = [];
27161
27162             for (var k in identifierProps) {
27163               var prop = identifierProps[k];
27164               var id = feature2.properties[prop];
27165               if (id) ids.push(id);
27166             }
27167
27168             if (feature2.properties.aliases) {
27169               for (var j in feature2.properties.aliases) {
27170                 ids.push(feature2.properties.aliases[j]);
27171               }
27172             }
27173
27174             for (var _i5 in ids) {
27175               var _id = canonicalID(ids[_i5]);
27176
27177               featuresByCode[_id] = feature2;
27178             }
27179           }
27180         }
27181
27182         function locArray(loc) {
27183           if (Array.isArray(loc)) {
27184             return loc;
27185           } else if (loc.coordinates) {
27186             return loc.coordinates;
27187           }
27188
27189           return loc.geometry.coordinates;
27190         }
27191
27192         function smallestFeature(loc) {
27193           var query = locArray(loc);
27194           var featureProperties = whichPolygonGetter(query);
27195           if (!featureProperties) return null;
27196           return featuresByCode[featureProperties.id];
27197         }
27198
27199         function countryFeature(loc) {
27200           var feature2 = smallestFeature(loc);
27201           if (!feature2) return null;
27202           var countryCode = feature2.properties.country || feature2.properties.iso1A2;
27203           return featuresByCode[countryCode] || null;
27204         }
27205
27206         var defaultOpts = {
27207           level: void 0,
27208           maxLevel: void 0,
27209           withProp: void 0
27210         };
27211
27212         function featureForLoc(loc, opts) {
27213           var targetLevel = opts.level || "country";
27214           var maxLevel = opts.maxLevel || "world";
27215           var withProp = opts.withProp;
27216           var targetLevelIndex = levels.indexOf(targetLevel);
27217           if (targetLevelIndex === -1) return null;
27218           var maxLevelIndex = levels.indexOf(maxLevel);
27219           if (maxLevelIndex === -1) return null;
27220           if (maxLevelIndex < targetLevelIndex) return null;
27221
27222           if (targetLevel === "country") {
27223             var fastFeature = countryFeature(loc);
27224
27225             if (fastFeature) {
27226               if (!withProp || fastFeature.properties[withProp]) {
27227                 return fastFeature;
27228               }
27229             }
27230           }
27231
27232           var features2 = featuresContaining(loc);
27233
27234           for (var i in features2) {
27235             var feature2 = features2[i];
27236             var levelIndex = levels.indexOf(feature2.properties.level);
27237
27238             if (feature2.properties.level === targetLevel || levelIndex > targetLevelIndex && levelIndex <= maxLevelIndex) {
27239               if (!withProp || feature2.properties[withProp]) {
27240                 return feature2;
27241               }
27242             }
27243           }
27244
27245           return null;
27246         }
27247
27248         function featureForID(id) {
27249           var stringID;
27250
27251           if (typeof id === "number") {
27252             stringID = id.toString();
27253
27254             if (stringID.length === 1) {
27255               stringID = "00" + stringID;
27256             } else if (stringID.length === 2) {
27257               stringID = "0" + stringID;
27258             }
27259           } else {
27260             stringID = canonicalID(id);
27261           }
27262
27263           return featuresByCode[stringID] || null;
27264         }
27265
27266         function smallestFeaturesForBbox(bbox) {
27267           return whichPolygonGetter.bbox(bbox).map(function (props) {
27268             return featuresByCode[props.id];
27269           });
27270         }
27271
27272         function smallestOrMatchingFeature(query) {
27273           if (_typeof(query) === "object") {
27274             return smallestFeature(query);
27275           }
27276
27277           return featureForID(query);
27278         }
27279
27280         function feature$1(query) {
27281           var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts;
27282
27283           if (_typeof(query) === "object") {
27284             return featureForLoc(query, opts);
27285           }
27286
27287           return featureForID(query);
27288         }
27289
27290         function iso1A2Code(query) {
27291           var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts;
27292           opts.withProp = "iso1A2";
27293           var match = feature$1(query, opts);
27294           if (!match) return null;
27295           return match.properties.iso1A2 || null;
27296         }
27297
27298         function featuresContaining(query, strict) {
27299           var matchingFeatures;
27300
27301           if (Array.isArray(query) && query.length === 4) {
27302             matchingFeatures = smallestFeaturesForBbox(query);
27303           } else {
27304             var smallestOrMatching = smallestOrMatchingFeature(query);
27305             matchingFeatures = smallestOrMatching ? [smallestOrMatching] : [];
27306           }
27307
27308           if (!matchingFeatures.length) return [];
27309           var returnFeatures;
27310
27311           if (!strict || _typeof(query) === "object") {
27312             returnFeatures = matchingFeatures.slice();
27313           } else {
27314             returnFeatures = [];
27315           }
27316
27317           for (var j in matchingFeatures) {
27318             var properties = matchingFeatures[j].properties;
27319
27320             for (var i in properties.groups) {
27321               var groupID = properties.groups[i];
27322               var groupFeature = featuresByCode[groupID];
27323
27324               if (returnFeatures.indexOf(groupFeature) === -1) {
27325                 returnFeatures.push(groupFeature);
27326               }
27327             }
27328           }
27329
27330           return returnFeatures;
27331         }
27332
27333         function featuresIn(id, strict) {
27334           var feature2 = featureForID(id);
27335           if (!feature2) return [];
27336           var features2 = [];
27337
27338           if (!strict) {
27339             features2.push(feature2);
27340           }
27341
27342           var properties = feature2.properties;
27343
27344           if (properties.members) {
27345             for (var i in properties.members) {
27346               var memberID = properties.members[i];
27347               features2.push(featuresByCode[memberID]);
27348             }
27349           }
27350
27351           return features2;
27352         }
27353
27354         function aggregateFeature(id) {
27355           var features2 = featuresIn(id, false);
27356           if (features2.length === 0) return null;
27357           var aggregateCoordinates = [];
27358
27359           for (var i in features2) {
27360             var feature2 = features2[i];
27361
27362             if (feature2.geometry && feature2.geometry.type === "MultiPolygon" && feature2.geometry.coordinates) {
27363               aggregateCoordinates = aggregateCoordinates.concat(feature2.geometry.coordinates);
27364             }
27365           }
27366
27367           return {
27368             type: "Feature",
27369             properties: features2[0].properties,
27370             geometry: {
27371               type: "MultiPolygon",
27372               coordinates: aggregateCoordinates
27373             }
27374           };
27375         }
27376
27377         function roadSpeedUnit(query) {
27378           var feature2 = smallestOrMatchingFeature(query);
27379           return feature2 && feature2.properties.roadSpeedUnit || null;
27380         }
27381
27382         var RADIUS = 6378137;
27383         var FLATTENING = 1 / 298.257223563;
27384         var POLAR_RADIUS = 6356752.3142;
27385         var wgs84 = {
27386           RADIUS: RADIUS,
27387           FLATTENING: FLATTENING,
27388           POLAR_RADIUS: POLAR_RADIUS
27389         };
27390
27391         var geometry_1 = geometry;
27392         var ring = ringArea;
27393
27394         function geometry(_) {
27395           var area = 0,
27396               i;
27397
27398           switch (_.type) {
27399             case 'Polygon':
27400               return polygonArea(_.coordinates);
27401
27402             case 'MultiPolygon':
27403               for (i = 0; i < _.coordinates.length; i++) {
27404                 area += polygonArea(_.coordinates[i]);
27405               }
27406
27407               return area;
27408
27409             case 'Point':
27410             case 'MultiPoint':
27411             case 'LineString':
27412             case 'MultiLineString':
27413               return 0;
27414
27415             case 'GeometryCollection':
27416               for (i = 0; i < _.geometries.length; i++) {
27417                 area += geometry(_.geometries[i]);
27418               }
27419
27420               return area;
27421           }
27422         }
27423
27424         function polygonArea(coords) {
27425           var area = 0;
27426
27427           if (coords && coords.length > 0) {
27428             area += Math.abs(ringArea(coords[0]));
27429
27430             for (var i = 1; i < coords.length; i++) {
27431               area -= Math.abs(ringArea(coords[i]));
27432             }
27433           }
27434
27435           return area;
27436         }
27437         /**
27438          * Calculate the approximate area of the polygon were it projected onto
27439          *     the earth.  Note that this area will be positive if ring is oriented
27440          *     clockwise, otherwise it will be negative.
27441          *
27442          * Reference:
27443          * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
27444          *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
27445          *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
27446          *
27447          * Returns:
27448          * {float} The approximate signed geodesic area of the polygon in square
27449          *     meters.
27450          */
27451
27452
27453         function ringArea(coords) {
27454           var p1,
27455               p2,
27456               p3,
27457               lowerIndex,
27458               middleIndex,
27459               upperIndex,
27460               i,
27461               area = 0,
27462               coordsLength = coords.length;
27463
27464           if (coordsLength > 2) {
27465             for (i = 0; i < coordsLength; i++) {
27466               if (i === coordsLength - 2) {
27467                 // i = N-2
27468                 lowerIndex = coordsLength - 2;
27469                 middleIndex = coordsLength - 1;
27470                 upperIndex = 0;
27471               } else if (i === coordsLength - 1) {
27472                 // i = N-1
27473                 lowerIndex = coordsLength - 1;
27474                 middleIndex = 0;
27475                 upperIndex = 1;
27476               } else {
27477                 // i = 0 to N-3
27478                 lowerIndex = i;
27479                 middleIndex = i + 1;
27480                 upperIndex = i + 2;
27481               }
27482
27483               p1 = coords[lowerIndex];
27484               p2 = coords[middleIndex];
27485               p3 = coords[upperIndex];
27486               area += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1]));
27487             }
27488
27489             area = area * wgs84.RADIUS * wgs84.RADIUS / 2;
27490           }
27491
27492           return area;
27493         }
27494
27495         function rad(_) {
27496           return _ * Math.PI / 180;
27497         }
27498
27499         var geojsonArea = {
27500           geometry: geometry_1,
27501           ring: ring
27502         };
27503
27504         var $includes = arrayIncludes.includes;
27505
27506
27507         // `Array.prototype.includes` method
27508         // https://tc39.es/ecma262/#sec-array.prototype.includes
27509         _export({ target: 'Array', proto: true }, {
27510           includes: function includes(el /* , fromIndex = 0 */) {
27511             return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
27512           }
27513         });
27514
27515         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
27516         addToUnscopables('includes');
27517
27518         var validateCenter_1$1 = function validateCenter(center) {
27519           var validCenterLengths = [2, 3];
27520
27521           if (!Array.isArray(center) || !validCenterLengths.includes(center.length)) {
27522             throw new Error("ERROR! Center has to be an array of length two or three");
27523           }
27524
27525           var _center = _slicedToArray(center, 2),
27526               lng = _center[0],
27527               lat = _center[1];
27528
27529           if (typeof lng !== "number" || typeof lat !== "number") {
27530             throw new Error("ERROR! Longitude and Latitude has to be numbers but where ".concat(_typeof(lng), " and ").concat(_typeof(lat)));
27531           }
27532
27533           if (lng > 180 || lng < -180) {
27534             throw new Error("ERROR! Longitude has to be between -180 and 180 but was ".concat(lng));
27535           }
27536
27537           if (lat > 90 || lat < -90) {
27538             throw new Error("ERROR! Latitude has to be between -90 and 90 but was ".concat(lat));
27539           }
27540         };
27541
27542         var validateCenter$1 = {
27543           validateCenter: validateCenter_1$1
27544         };
27545
27546         var validateRadius_1$1 = function validateRadius(radius) {
27547           if (typeof radius !== "number") {
27548             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(_typeof(radius)));
27549           }
27550
27551           if (radius <= 0) {
27552             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(radius));
27553           }
27554         };
27555
27556         var validateRadius$1 = {
27557           validateRadius: validateRadius_1$1
27558         };
27559
27560         var validateNumberOfEdges_1$1 = function validateNumberOfEdges(numberOfEdges) {
27561           if (typeof numberOfEdges !== "number") {
27562             var ARGUMENT_TYPE = Array.isArray(numberOfEdges) ? "array" : _typeof(numberOfEdges);
27563             throw new Error("ERROR! Number of edges has to be a number but was: ".concat(ARGUMENT_TYPE));
27564           }
27565
27566           if (numberOfEdges < 3) {
27567             throw new Error("ERROR! Number of edges has to be at least 3 but was: ".concat(numberOfEdges));
27568           }
27569         };
27570
27571         var validateNumberOfEdges$1 = {
27572           validateNumberOfEdges: validateNumberOfEdges_1$1
27573         };
27574
27575         var validateEarthRadius_1$1 = function validateEarthRadius(earthRadius) {
27576           if (typeof earthRadius !== "number") {
27577             var ARGUMENT_TYPE = Array.isArray(earthRadius) ? "array" : _typeof(earthRadius);
27578             throw new Error("ERROR! Earth radius has to be a number but was: ".concat(ARGUMENT_TYPE));
27579           }
27580
27581           if (earthRadius <= 0) {
27582             throw new Error("ERROR! Earth radius has to be a positive number but was: ".concat(earthRadius));
27583           }
27584         };
27585
27586         var validateEarthRadius$1 = {
27587           validateEarthRadius: validateEarthRadius_1$1
27588         };
27589
27590         var validateBearing_1$1 = function validateBearing(bearing) {
27591           if (typeof bearing !== "number") {
27592             var ARGUMENT_TYPE = Array.isArray(bearing) ? "array" : _typeof(bearing);
27593             throw new Error("ERROR! Bearing has to be a number but was: ".concat(ARGUMENT_TYPE));
27594           }
27595         };
27596
27597         var validateBearing$1 = {
27598           validateBearing: validateBearing_1$1
27599         };
27600
27601         var validateCenter = validateCenter$1.validateCenter;
27602         var validateRadius = validateRadius$1.validateRadius;
27603         var validateNumberOfEdges = validateNumberOfEdges$1.validateNumberOfEdges;
27604         var validateEarthRadius = validateEarthRadius$1.validateEarthRadius;
27605         var validateBearing = validateBearing$1.validateBearing;
27606
27607         function validateInput$1(_ref) {
27608           var center = _ref.center,
27609               radius = _ref.radius,
27610               numberOfEdges = _ref.numberOfEdges,
27611               earthRadius = _ref.earthRadius,
27612               bearing = _ref.bearing;
27613           validateCenter(center);
27614           validateRadius(radius);
27615           validateNumberOfEdges(numberOfEdges);
27616           validateEarthRadius(earthRadius);
27617           validateBearing(bearing);
27618         }
27619
27620         var validateCenter_1 = validateCenter;
27621         var validateRadius_1 = validateRadius;
27622         var validateNumberOfEdges_1 = validateNumberOfEdges;
27623         var validateEarthRadius_1 = validateEarthRadius;
27624         var validateBearing_1 = validateBearing;
27625         var validateInput_1 = validateInput$1;
27626         var inputValidation = {
27627           validateCenter: validateCenter_1,
27628           validateRadius: validateRadius_1,
27629           validateNumberOfEdges: validateNumberOfEdges_1,
27630           validateEarthRadius: validateEarthRadius_1,
27631           validateBearing: validateBearing_1,
27632           validateInput: validateInput_1
27633         };
27634
27635         var validateInput = inputValidation.validateInput;
27636         var defaultEarthRadius = 6378137; // equatorial Earth radius
27637
27638         function toRadians(angleInDegrees) {
27639           return angleInDegrees * Math.PI / 180;
27640         }
27641
27642         function toDegrees(angleInRadians) {
27643           return angleInRadians * 180 / Math.PI;
27644         }
27645
27646         function offset(c1, distance, earthRadius, bearing) {
27647           var lat1 = toRadians(c1[1]);
27648           var lon1 = toRadians(c1[0]);
27649           var dByR = distance / earthRadius;
27650           var lat = Math.asin(Math.sin(lat1) * Math.cos(dByR) + Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));
27651           var lon = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));
27652           return [toDegrees(lon), toDegrees(lat)];
27653         }
27654
27655         var circleToPolygon = function circleToPolygon(center, radius, options) {
27656           var n = getNumberOfEdges(options);
27657           var earthRadius = getEarthRadius(options);
27658           var bearing = getBearing(options);
27659           var direction = getDirection(options); // validateInput() throws error on invalid input and do nothing on valid input
27660
27661           validateInput({
27662             center: center,
27663             radius: radius,
27664             numberOfEdges: n,
27665             earthRadius: earthRadius,
27666             bearing: bearing
27667           });
27668           var start = toRadians(bearing);
27669           var coordinates = [];
27670
27671           for (var i = 0; i < n; ++i) {
27672             coordinates.push(offset(center, radius, earthRadius, start + direction * 2 * Math.PI * -i / n));
27673           }
27674
27675           coordinates.push(coordinates[0]);
27676           return {
27677             type: "Polygon",
27678             coordinates: [coordinates]
27679           };
27680         };
27681
27682         function getNumberOfEdges(options) {
27683           if (isUndefinedOrNull(options)) {
27684             return 32;
27685           } else if (isObjectNotArray(options)) {
27686             var numberOfEdges = options.numberOfEdges;
27687             return numberOfEdges === undefined ? 32 : numberOfEdges;
27688           }
27689
27690           return options;
27691         }
27692
27693         function getEarthRadius(options) {
27694           if (isUndefinedOrNull(options)) {
27695             return defaultEarthRadius;
27696           } else if (isObjectNotArray(options)) {
27697             var earthRadius = options.earthRadius;
27698             return earthRadius === undefined ? defaultEarthRadius : earthRadius;
27699           }
27700
27701           return defaultEarthRadius;
27702         }
27703
27704         function getDirection(options) {
27705           if (isObjectNotArray(options) && options.rightHandRule) {
27706             return -1;
27707           }
27708
27709           return 1;
27710         }
27711
27712         function getBearing(options) {
27713           if (isUndefinedOrNull(options)) {
27714             return 0;
27715           } else if (isObjectNotArray(options)) {
27716             var bearing = options.bearing;
27717             return bearing === undefined ? 0 : bearing;
27718           }
27719
27720           return 0;
27721         }
27722
27723         function isObjectNotArray(argument) {
27724           return argument !== null && _typeof(argument) === "object" && !Array.isArray(argument);
27725         }
27726
27727         function isUndefinedOrNull(argument) {
27728           return argument === null || argument === undefined;
27729         }
27730
27731         // `Number.EPSILON` constant
27732         // https://tc39.es/ecma262/#sec-number.epsilon
27733         _export({ target: 'Number', stat: true }, {
27734           EPSILON: Math.pow(2, -52)
27735         });
27736
27737         var quot = /"/g;
27738
27739         // `CreateHTML` abstract operation
27740         // https://tc39.es/ecma262/#sec-createhtml
27741         var createHtml = function (string, tag, attribute, value) {
27742           var S = String(requireObjectCoercible(string));
27743           var p1 = '<' + tag;
27744           if (attribute !== '') p1 += ' ' + attribute + '="' + String(value).replace(quot, '&quot;') + '"';
27745           return p1 + '>' + S + '</' + tag + '>';
27746         };
27747
27748         // check the existence of a method, lowercase
27749         // of a tag and escaping quotes in arguments
27750         var stringHtmlForced = function (METHOD_NAME) {
27751           return fails(function () {
27752             var test = ''[METHOD_NAME]('"');
27753             return test !== test.toLowerCase() || test.split('"').length > 3;
27754           });
27755         };
27756
27757         // `String.prototype.link` method
27758         // https://tc39.es/ecma262/#sec-string.prototype.link
27759         _export({ target: 'String', proto: true, forced: stringHtmlForced('link') }, {
27760           link: function link(url) {
27761             return createHtml(this, 'a', 'href', url);
27762           }
27763         });
27764
27765         /**
27766          * splaytree v3.1.0
27767          * Fast Splay tree for Node and browser
27768          *
27769          * @author Alexander Milevski <info@w8r.name>
27770          * @license MIT
27771          * @preserve
27772          */
27773         var Node$1 =
27774         /** @class */
27775         function () {
27776           function Node(key, data) {
27777             this.next = null;
27778             this.key = key;
27779             this.data = data;
27780             this.left = null;
27781             this.right = null;
27782           }
27783
27784           return Node;
27785         }();
27786         /* follows "An implementation of top-down splaying"
27787          * by D. Sleator <sleator@cs.cmu.edu> March 1992
27788          */
27789
27790
27791         function DEFAULT_COMPARE(a, b) {
27792           return a > b ? 1 : a < b ? -1 : 0;
27793         }
27794         /**
27795          * Simple top down splay, not requiring i to be in the tree t.
27796          */
27797
27798
27799         function splay(i, t, comparator) {
27800           var N = new Node$1(null, null);
27801           var l = N;
27802           var r = N;
27803
27804           while (true) {
27805             var cmp = comparator(i, t.key); //if (i < t.key) {
27806
27807             if (cmp < 0) {
27808               if (t.left === null) break; //if (i < t.left.key) {
27809
27810               if (comparator(i, t.left.key) < 0) {
27811                 var y = t.left;
27812                 /* rotate right */
27813
27814                 t.left = y.right;
27815                 y.right = t;
27816                 t = y;
27817                 if (t.left === null) break;
27818               }
27819
27820               r.left = t;
27821               /* link right */
27822
27823               r = t;
27824               t = t.left; //} else if (i > t.key) {
27825             } else if (cmp > 0) {
27826               if (t.right === null) break; //if (i > t.right.key) {
27827
27828               if (comparator(i, t.right.key) > 0) {
27829                 var y = t.right;
27830                 /* rotate left */
27831
27832                 t.right = y.left;
27833                 y.left = t;
27834                 t = y;
27835                 if (t.right === null) break;
27836               }
27837
27838               l.right = t;
27839               /* link left */
27840
27841               l = t;
27842               t = t.right;
27843             } else break;
27844           }
27845           /* assemble */
27846
27847
27848           l.right = t.left;
27849           r.left = t.right;
27850           t.left = N.right;
27851           t.right = N.left;
27852           return t;
27853         }
27854
27855         function insert(i, data, t, comparator) {
27856           var node = new Node$1(i, data);
27857
27858           if (t === null) {
27859             node.left = node.right = null;
27860             return node;
27861           }
27862
27863           t = splay(i, t, comparator);
27864           var cmp = comparator(i, t.key);
27865
27866           if (cmp < 0) {
27867             node.left = t.left;
27868             node.right = t;
27869             t.left = null;
27870           } else if (cmp >= 0) {
27871             node.right = t.right;
27872             node.left = t;
27873             t.right = null;
27874           }
27875
27876           return node;
27877         }
27878
27879         function split$1(key, v, comparator) {
27880           var left = null;
27881           var right = null;
27882
27883           if (v) {
27884             v = splay(key, v, comparator);
27885             var cmp = comparator(v.key, key);
27886
27887             if (cmp === 0) {
27888               left = v.left;
27889               right = v.right;
27890             } else if (cmp < 0) {
27891               right = v.right;
27892               v.right = null;
27893               left = v;
27894             } else {
27895               left = v.left;
27896               v.left = null;
27897               right = v;
27898             }
27899           }
27900
27901           return {
27902             left: left,
27903             right: right
27904           };
27905         }
27906
27907         function merge$3(left, right, comparator) {
27908           if (right === null) return left;
27909           if (left === null) return right;
27910           right = splay(left.key, right, comparator);
27911           right.left = left;
27912           return right;
27913         }
27914         /**
27915          * Prints level of the tree
27916          */
27917
27918
27919         function printRow(root, prefix, isTail, out, printNode) {
27920           if (root) {
27921             out("" + prefix + (isTail ? '└── ' : '├── ') + printNode(root) + "\n");
27922             var indent = prefix + (isTail ? '    ' : '│   ');
27923             if (root.left) printRow(root.left, indent, false, out, printNode);
27924             if (root.right) printRow(root.right, indent, true, out, printNode);
27925           }
27926         }
27927
27928         var Tree =
27929         /** @class */
27930         function () {
27931           function Tree(comparator) {
27932             if (comparator === void 0) {
27933               comparator = DEFAULT_COMPARE;
27934             }
27935
27936             this._root = null;
27937             this._size = 0;
27938             this._comparator = comparator;
27939           }
27940           /**
27941            * Inserts a key, allows duplicates
27942            */
27943
27944
27945           Tree.prototype.insert = function (key, data) {
27946             this._size++;
27947             return this._root = insert(key, data, this._root, this._comparator);
27948           };
27949           /**
27950            * Adds a key, if it is not present in the tree
27951            */
27952
27953
27954           Tree.prototype.add = function (key, data) {
27955             var node = new Node$1(key, data);
27956
27957             if (this._root === null) {
27958               node.left = node.right = null;
27959               this._size++;
27960               this._root = node;
27961             }
27962
27963             var comparator = this._comparator;
27964             var t = splay(key, this._root, comparator);
27965             var cmp = comparator(key, t.key);
27966             if (cmp === 0) this._root = t;else {
27967               if (cmp < 0) {
27968                 node.left = t.left;
27969                 node.right = t;
27970                 t.left = null;
27971               } else if (cmp > 0) {
27972                 node.right = t.right;
27973                 node.left = t;
27974                 t.right = null;
27975               }
27976
27977               this._size++;
27978               this._root = node;
27979             }
27980             return this._root;
27981           };
27982           /**
27983            * @param  {Key} key
27984            * @return {Node|null}
27985            */
27986
27987
27988           Tree.prototype.remove = function (key) {
27989             this._root = this._remove(key, this._root, this._comparator);
27990           };
27991           /**
27992            * Deletes i from the tree if it's there
27993            */
27994
27995
27996           Tree.prototype._remove = function (i, t, comparator) {
27997             var x;
27998             if (t === null) return null;
27999             t = splay(i, t, comparator);
28000             var cmp = comparator(i, t.key);
28001
28002             if (cmp === 0) {
28003               /* found it */
28004               if (t.left === null) {
28005                 x = t.right;
28006               } else {
28007                 x = splay(i, t.left, comparator);
28008                 x.right = t.right;
28009               }
28010
28011               this._size--;
28012               return x;
28013             }
28014
28015             return t;
28016             /* It wasn't there */
28017           };
28018           /**
28019            * Removes and returns the node with smallest key
28020            */
28021
28022
28023           Tree.prototype.pop = function () {
28024             var node = this._root;
28025
28026             if (node) {
28027               while (node.left) {
28028                 node = node.left;
28029               }
28030
28031               this._root = splay(node.key, this._root, this._comparator);
28032               this._root = this._remove(node.key, this._root, this._comparator);
28033               return {
28034                 key: node.key,
28035                 data: node.data
28036               };
28037             }
28038
28039             return null;
28040           };
28041           /**
28042            * Find without splaying
28043            */
28044
28045
28046           Tree.prototype.findStatic = function (key) {
28047             var current = this._root;
28048             var compare = this._comparator;
28049
28050             while (current) {
28051               var cmp = compare(key, current.key);
28052               if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
28053             }
28054
28055             return null;
28056           };
28057
28058           Tree.prototype.find = function (key) {
28059             if (this._root) {
28060               this._root = splay(key, this._root, this._comparator);
28061               if (this._comparator(key, this._root.key) !== 0) return null;
28062             }
28063
28064             return this._root;
28065           };
28066
28067           Tree.prototype.contains = function (key) {
28068             var current = this._root;
28069             var compare = this._comparator;
28070
28071             while (current) {
28072               var cmp = compare(key, current.key);
28073               if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
28074             }
28075
28076             return false;
28077           };
28078
28079           Tree.prototype.forEach = function (visitor, ctx) {
28080             var current = this._root;
28081             var Q = [];
28082             /* Initialize stack s */
28083
28084             var done = false;
28085
28086             while (!done) {
28087               if (current !== null) {
28088                 Q.push(current);
28089                 current = current.left;
28090               } else {
28091                 if (Q.length !== 0) {
28092                   current = Q.pop();
28093                   visitor.call(ctx, current);
28094                   current = current.right;
28095                 } else done = true;
28096               }
28097             }
28098
28099             return this;
28100           };
28101           /**
28102            * Walk key range from `low` to `high`. Stops if `fn` returns a value.
28103            */
28104
28105
28106           Tree.prototype.range = function (low, high, fn, ctx) {
28107             var Q = [];
28108             var compare = this._comparator;
28109             var node = this._root;
28110             var cmp;
28111
28112             while (Q.length !== 0 || node) {
28113               if (node) {
28114                 Q.push(node);
28115                 node = node.left;
28116               } else {
28117                 node = Q.pop();
28118                 cmp = compare(node.key, high);
28119
28120                 if (cmp > 0) {
28121                   break;
28122                 } else if (compare(node.key, low) >= 0) {
28123                   if (fn.call(ctx, node)) return this; // stop if smth is returned
28124                 }
28125
28126                 node = node.right;
28127               }
28128             }
28129
28130             return this;
28131           };
28132           /**
28133            * Returns array of keys
28134            */
28135
28136
28137           Tree.prototype.keys = function () {
28138             var keys = [];
28139             this.forEach(function (_a) {
28140               var key = _a.key;
28141               return keys.push(key);
28142             });
28143             return keys;
28144           };
28145           /**
28146            * Returns array of all the data in the nodes
28147            */
28148
28149
28150           Tree.prototype.values = function () {
28151             var values = [];
28152             this.forEach(function (_a) {
28153               var data = _a.data;
28154               return values.push(data);
28155             });
28156             return values;
28157           };
28158
28159           Tree.prototype.min = function () {
28160             if (this._root) return this.minNode(this._root).key;
28161             return null;
28162           };
28163
28164           Tree.prototype.max = function () {
28165             if (this._root) return this.maxNode(this._root).key;
28166             return null;
28167           };
28168
28169           Tree.prototype.minNode = function (t) {
28170             if (t === void 0) {
28171               t = this._root;
28172             }
28173
28174             if (t) while (t.left) {
28175               t = t.left;
28176             }
28177             return t;
28178           };
28179
28180           Tree.prototype.maxNode = function (t) {
28181             if (t === void 0) {
28182               t = this._root;
28183             }
28184
28185             if (t) while (t.right) {
28186               t = t.right;
28187             }
28188             return t;
28189           };
28190           /**
28191            * Returns node at given index
28192            */
28193
28194
28195           Tree.prototype.at = function (index) {
28196             var current = this._root;
28197             var done = false;
28198             var i = 0;
28199             var Q = [];
28200
28201             while (!done) {
28202               if (current) {
28203                 Q.push(current);
28204                 current = current.left;
28205               } else {
28206                 if (Q.length > 0) {
28207                   current = Q.pop();
28208                   if (i === index) return current;
28209                   i++;
28210                   current = current.right;
28211                 } else done = true;
28212               }
28213             }
28214
28215             return null;
28216           };
28217
28218           Tree.prototype.next = function (d) {
28219             var root = this._root;
28220             var successor = null;
28221
28222             if (d.right) {
28223               successor = d.right;
28224
28225               while (successor.left) {
28226                 successor = successor.left;
28227               }
28228
28229               return successor;
28230             }
28231
28232             var comparator = this._comparator;
28233
28234             while (root) {
28235               var cmp = comparator(d.key, root.key);
28236               if (cmp === 0) break;else if (cmp < 0) {
28237                 successor = root;
28238                 root = root.left;
28239               } else root = root.right;
28240             }
28241
28242             return successor;
28243           };
28244
28245           Tree.prototype.prev = function (d) {
28246             var root = this._root;
28247             var predecessor = null;
28248
28249             if (d.left !== null) {
28250               predecessor = d.left;
28251
28252               while (predecessor.right) {
28253                 predecessor = predecessor.right;
28254               }
28255
28256               return predecessor;
28257             }
28258
28259             var comparator = this._comparator;
28260
28261             while (root) {
28262               var cmp = comparator(d.key, root.key);
28263               if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
28264                 predecessor = root;
28265                 root = root.right;
28266               }
28267             }
28268
28269             return predecessor;
28270           };
28271
28272           Tree.prototype.clear = function () {
28273             this._root = null;
28274             this._size = 0;
28275             return this;
28276           };
28277
28278           Tree.prototype.toList = function () {
28279             return toList(this._root);
28280           };
28281           /**
28282            * Bulk-load items. Both array have to be same size
28283            */
28284
28285
28286           Tree.prototype.load = function (keys, values, presort) {
28287             if (values === void 0) {
28288               values = [];
28289             }
28290
28291             if (presort === void 0) {
28292               presort = false;
28293             }
28294
28295             var size = keys.length;
28296             var comparator = this._comparator; // sort if needed
28297
28298             if (presort) sort(keys, values, 0, size - 1, comparator);
28299
28300             if (this._root === null) {
28301               // empty tree
28302               this._root = loadRecursive(keys, values, 0, size);
28303               this._size = size;
28304             } else {
28305               // that re-builds the whole tree from two in-order traversals
28306               var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
28307               size = this._size + size;
28308               this._root = sortedListToBST({
28309                 head: mergedList
28310               }, 0, size);
28311             }
28312
28313             return this;
28314           };
28315
28316           Tree.prototype.isEmpty = function () {
28317             return this._root === null;
28318           };
28319
28320           Object.defineProperty(Tree.prototype, "size", {
28321             get: function get() {
28322               return this._size;
28323             },
28324             enumerable: true,
28325             configurable: true
28326           });
28327           Object.defineProperty(Tree.prototype, "root", {
28328             get: function get() {
28329               return this._root;
28330             },
28331             enumerable: true,
28332             configurable: true
28333           });
28334
28335           Tree.prototype.toString = function (printNode) {
28336             if (printNode === void 0) {
28337               printNode = function printNode(n) {
28338                 return String(n.key);
28339               };
28340             }
28341
28342             var out = [];
28343             printRow(this._root, '', true, function (v) {
28344               return out.push(v);
28345             }, printNode);
28346             return out.join('');
28347           };
28348
28349           Tree.prototype.update = function (key, newKey, newData) {
28350             var comparator = this._comparator;
28351
28352             var _a = split$1(key, this._root, comparator),
28353                 left = _a.left,
28354                 right = _a.right;
28355
28356             if (comparator(key, newKey) < 0) {
28357               right = insert(newKey, newData, right, comparator);
28358             } else {
28359               left = insert(newKey, newData, left, comparator);
28360             }
28361
28362             this._root = merge$3(left, right, comparator);
28363           };
28364
28365           Tree.prototype.split = function (key) {
28366             return split$1(key, this._root, this._comparator);
28367           };
28368
28369           return Tree;
28370         }();
28371
28372         function loadRecursive(keys, values, start, end) {
28373           var size = end - start;
28374
28375           if (size > 0) {
28376             var middle = start + Math.floor(size / 2);
28377             var key = keys[middle];
28378             var data = values[middle];
28379             var node = new Node$1(key, data);
28380             node.left = loadRecursive(keys, values, start, middle);
28381             node.right = loadRecursive(keys, values, middle + 1, end);
28382             return node;
28383           }
28384
28385           return null;
28386         }
28387
28388         function createList(keys, values) {
28389           var head = new Node$1(null, null);
28390           var p = head;
28391
28392           for (var i = 0; i < keys.length; i++) {
28393             p = p.next = new Node$1(keys[i], values[i]);
28394           }
28395
28396           p.next = null;
28397           return head.next;
28398         }
28399
28400         function toList(root) {
28401           var current = root;
28402           var Q = [];
28403           var done = false;
28404           var head = new Node$1(null, null);
28405           var p = head;
28406
28407           while (!done) {
28408             if (current) {
28409               Q.push(current);
28410               current = current.left;
28411             } else {
28412               if (Q.length > 0) {
28413                 current = p = p.next = Q.pop();
28414                 current = current.right;
28415               } else done = true;
28416             }
28417           }
28418
28419           p.next = null; // that'll work even if the tree was empty
28420
28421           return head.next;
28422         }
28423
28424         function sortedListToBST(list, start, end) {
28425           var size = end - start;
28426
28427           if (size > 0) {
28428             var middle = start + Math.floor(size / 2);
28429             var left = sortedListToBST(list, start, middle);
28430             var root = list.head;
28431             root.left = left;
28432             list.head = list.head.next;
28433             root.right = sortedListToBST(list, middle + 1, end);
28434             return root;
28435           }
28436
28437           return null;
28438         }
28439
28440         function mergeLists(l1, l2, compare) {
28441           var head = new Node$1(null, null); // dummy
28442
28443           var p = head;
28444           var p1 = l1;
28445           var p2 = l2;
28446
28447           while (p1 !== null && p2 !== null) {
28448             if (compare(p1.key, p2.key) < 0) {
28449               p.next = p1;
28450               p1 = p1.next;
28451             } else {
28452               p.next = p2;
28453               p2 = p2.next;
28454             }
28455
28456             p = p.next;
28457           }
28458
28459           if (p1 !== null) {
28460             p.next = p1;
28461           } else if (p2 !== null) {
28462             p.next = p2;
28463           }
28464
28465           return head.next;
28466         }
28467
28468         function sort(keys, values, left, right, compare) {
28469           if (left >= right) return;
28470           var pivot = keys[left + right >> 1];
28471           var i = left - 1;
28472           var j = right + 1;
28473
28474           while (true) {
28475             do {
28476               i++;
28477             } while (compare(keys[i], pivot) < 0);
28478
28479             do {
28480               j--;
28481             } while (compare(keys[j], pivot) > 0);
28482
28483             if (i >= j) break;
28484             var tmp = keys[i];
28485             keys[i] = keys[j];
28486             keys[j] = tmp;
28487             tmp = values[i];
28488             values[i] = values[j];
28489             values[j] = tmp;
28490           }
28491
28492           sort(keys, values, left, j, compare);
28493           sort(keys, values, j + 1, right, compare);
28494         }
28495
28496         function _classCallCheck(instance, Constructor) {
28497           if (!(instance instanceof Constructor)) {
28498             throw new TypeError("Cannot call a class as a function");
28499           }
28500         }
28501
28502         function _defineProperties(target, props) {
28503           for (var i = 0; i < props.length; i++) {
28504             var descriptor = props[i];
28505             descriptor.enumerable = descriptor.enumerable || false;
28506             descriptor.configurable = true;
28507             if ("value" in descriptor) descriptor.writable = true;
28508             Object.defineProperty(target, descriptor.key, descriptor);
28509           }
28510         }
28511
28512         function _createClass(Constructor, protoProps, staticProps) {
28513           if (protoProps) _defineProperties(Constructor.prototype, protoProps);
28514           if (staticProps) _defineProperties(Constructor, staticProps);
28515           return Constructor;
28516         }
28517         /**
28518          * A bounding box has the format:
28519          *
28520          *  { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
28521          *
28522          */
28523
28524
28525         var isInBbox = function isInBbox(bbox, point) {
28526           return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
28527         };
28528         /* Returns either null, or a bbox (aka an ordered pair of points)
28529          * If there is only one point of overlap, a bbox with identical points
28530          * will be returned */
28531
28532
28533         var getBboxOverlap = function getBboxOverlap(b1, b2) {
28534           // check if the bboxes overlap at all
28535           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; // find the middle two X values
28536
28537           var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
28538           var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x; // find the middle two Y values
28539
28540           var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
28541           var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y; // put those middle values together to get the overlap
28542
28543           return {
28544             ll: {
28545               x: lowerX,
28546               y: lowerY
28547             },
28548             ur: {
28549               x: upperX,
28550               y: upperY
28551             }
28552           };
28553         };
28554         /* Javascript doesn't do integer math. Everything is
28555          * floating point with percision Number.EPSILON.
28556          *
28557          * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
28558          */
28559
28560
28561         var epsilon = Number.EPSILON; // IE Polyfill
28562
28563         if (epsilon === undefined) epsilon = Math.pow(2, -52);
28564         var EPSILON_SQ = epsilon * epsilon;
28565         /* FLP comparator */
28566
28567         var cmp = function cmp(a, b) {
28568           // check if they're both 0
28569           if (-epsilon < a && a < epsilon) {
28570             if (-epsilon < b && b < epsilon) {
28571               return 0;
28572             }
28573           } // check if they're flp equal
28574
28575
28576           var ab = a - b;
28577
28578           if (ab * ab < EPSILON_SQ * a * b) {
28579             return 0;
28580           } // normal comparison
28581
28582
28583           return a < b ? -1 : 1;
28584         };
28585         /**
28586          * This class rounds incoming values sufficiently so that
28587          * floating points problems are, for the most part, avoided.
28588          *
28589          * Incoming points are have their x & y values tested against
28590          * all previously seen x & y values. If either is 'too close'
28591          * to a previously seen value, it's value is 'snapped' to the
28592          * previously seen value.
28593          *
28594          * All points should be rounded by this class before being
28595          * stored in any data structures in the rest of this algorithm.
28596          */
28597
28598
28599         var PtRounder = /*#__PURE__*/function () {
28600           function PtRounder() {
28601             _classCallCheck(this, PtRounder);
28602
28603             this.reset();
28604           }
28605
28606           _createClass(PtRounder, [{
28607             key: "reset",
28608             value: function reset() {
28609               this.xRounder = new CoordRounder();
28610               this.yRounder = new CoordRounder();
28611             }
28612           }, {
28613             key: "round",
28614             value: function round(x, y) {
28615               return {
28616                 x: this.xRounder.round(x),
28617                 y: this.yRounder.round(y)
28618               };
28619             }
28620           }]);
28621
28622           return PtRounder;
28623         }();
28624
28625         var CoordRounder = /*#__PURE__*/function () {
28626           function CoordRounder() {
28627             _classCallCheck(this, CoordRounder);
28628
28629             this.tree = new Tree(); // preseed with 0 so we don't end up with values < Number.EPSILON
28630
28631             this.round(0);
28632           } // Note: this can rounds input values backwards or forwards.
28633           //       You might ask, why not restrict this to just rounding
28634           //       forwards? Wouldn't that allow left endpoints to always
28635           //       remain left endpoints during splitting (never change to
28636           //       right). No - it wouldn't, because we snap intersections
28637           //       to endpoints (to establish independence from the segment
28638           //       angle for t-intersections).
28639
28640
28641           _createClass(CoordRounder, [{
28642             key: "round",
28643             value: function round(coord) {
28644               var node = this.tree.add(coord);
28645               var prevNode = this.tree.prev(node);
28646
28647               if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
28648                 this.tree.remove(coord);
28649                 return prevNode.key;
28650               }
28651
28652               var nextNode = this.tree.next(node);
28653
28654               if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
28655                 this.tree.remove(coord);
28656                 return nextNode.key;
28657               }
28658
28659               return coord;
28660             }
28661           }]);
28662
28663           return CoordRounder;
28664         }(); // singleton available by import
28665
28666
28667         var rounder = new PtRounder();
28668         /* Cross Product of two vectors with first point at origin */
28669
28670         var crossProduct = function crossProduct(a, b) {
28671           return a.x * b.y - a.y * b.x;
28672         };
28673         /* Dot Product of two vectors with first point at origin */
28674
28675
28676         var dotProduct = function dotProduct(a, b) {
28677           return a.x * b.x + a.y * b.y;
28678         };
28679         /* Comparator for two vectors with same starting point */
28680
28681
28682         var compareVectorAngles = function compareVectorAngles(basePt, endPt1, endPt2) {
28683           var v1 = {
28684             x: endPt1.x - basePt.x,
28685             y: endPt1.y - basePt.y
28686           };
28687           var v2 = {
28688             x: endPt2.x - basePt.x,
28689             y: endPt2.y - basePt.y
28690           };
28691           var kross = crossProduct(v1, v2);
28692           return cmp(kross, 0);
28693         };
28694
28695         var length = function length(v) {
28696           return Math.sqrt(dotProduct(v, v));
28697         };
28698         /* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
28699
28700
28701         var sineOfAngle = function sineOfAngle(pShared, pBase, pAngle) {
28702           var vBase = {
28703             x: pBase.x - pShared.x,
28704             y: pBase.y - pShared.y
28705           };
28706           var vAngle = {
28707             x: pAngle.x - pShared.x,
28708             y: pAngle.y - pShared.y
28709           };
28710           return crossProduct(vAngle, vBase) / length(vAngle) / length(vBase);
28711         };
28712         /* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
28713
28714
28715         var cosineOfAngle = function cosineOfAngle(pShared, pBase, pAngle) {
28716           var vBase = {
28717             x: pBase.x - pShared.x,
28718             y: pBase.y - pShared.y
28719           };
28720           var vAngle = {
28721             x: pAngle.x - pShared.x,
28722             y: pAngle.y - pShared.y
28723           };
28724           return dotProduct(vAngle, vBase) / length(vAngle) / length(vBase);
28725         };
28726         /* Get the x coordinate where the given line (defined by a point and vector)
28727          * crosses the horizontal line with the given y coordiante.
28728          * In the case of parrallel lines (including overlapping ones) returns null. */
28729
28730
28731         var horizontalIntersection = function horizontalIntersection(pt, v, y) {
28732           if (v.y === 0) return null;
28733           return {
28734             x: pt.x + v.x / v.y * (y - pt.y),
28735             y: y
28736           };
28737         };
28738         /* Get the y coordinate where the given line (defined by a point and vector)
28739          * crosses the vertical line with the given x coordiante.
28740          * In the case of parrallel lines (including overlapping ones) returns null. */
28741
28742
28743         var verticalIntersection = function verticalIntersection(pt, v, x) {
28744           if (v.x === 0) return null;
28745           return {
28746             x: x,
28747             y: pt.y + v.y / v.x * (x - pt.x)
28748           };
28749         };
28750         /* Get the intersection of two lines, each defined by a base point and a vector.
28751          * In the case of parrallel lines (including overlapping ones) returns null. */
28752
28753
28754         var intersection = function intersection(pt1, v1, pt2, v2) {
28755           // take some shortcuts for vertical and horizontal lines
28756           // this also ensures we don't calculate an intersection and then discover
28757           // it's actually outside the bounding box of the line
28758           if (v1.x === 0) return verticalIntersection(pt2, v2, pt1.x);
28759           if (v2.x === 0) return verticalIntersection(pt1, v1, pt2.x);
28760           if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
28761           if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y); // General case for non-overlapping segments.
28762           // This algorithm is based on Schneider and Eberly.
28763           // http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
28764
28765           var kross = crossProduct(v1, v2);
28766           if (kross == 0) return null;
28767           var ve = {
28768             x: pt2.x - pt1.x,
28769             y: pt2.y - pt1.y
28770           };
28771           var d1 = crossProduct(ve, v1) / kross;
28772           var d2 = crossProduct(ve, v2) / kross; // take the average of the two calculations to minimize rounding error
28773
28774           var x1 = pt1.x + d2 * v1.x,
28775               x2 = pt2.x + d1 * v2.x;
28776           var y1 = pt1.y + d2 * v1.y,
28777               y2 = pt2.y + d1 * v2.y;
28778           var x = (x1 + x2) / 2;
28779           var y = (y1 + y2) / 2;
28780           return {
28781             x: x,
28782             y: y
28783           };
28784         };
28785
28786         var SweepEvent = /*#__PURE__*/function () {
28787           _createClass(SweepEvent, null, [{
28788             key: "compare",
28789             // for ordering sweep events in the sweep event queue
28790             value: function compare(a, b) {
28791               // favor event with a point that the sweep line hits first
28792               var ptCmp = SweepEvent.comparePoints(a.point, b.point);
28793               if (ptCmp !== 0) return ptCmp; // the points are the same, so link them if needed
28794
28795               if (a.point !== b.point) a.link(b); // favor right events over left
28796
28797               if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1; // we have two matching left or right endpoints
28798               // ordering of this case is the same as for their segments
28799
28800               return Segment.compare(a.segment, b.segment);
28801             } // for ordering points in sweep line order
28802
28803           }, {
28804             key: "comparePoints",
28805             value: function comparePoints(aPt, bPt) {
28806               if (aPt.x < bPt.x) return -1;
28807               if (aPt.x > bPt.x) return 1;
28808               if (aPt.y < bPt.y) return -1;
28809               if (aPt.y > bPt.y) return 1;
28810               return 0;
28811             } // Warning: 'point' input will be modified and re-used (for performance)
28812
28813           }]);
28814
28815           function SweepEvent(point, isLeft) {
28816             _classCallCheck(this, SweepEvent);
28817
28818             if (point.events === undefined) point.events = [this];else point.events.push(this);
28819             this.point = point;
28820             this.isLeft = isLeft; // this.segment, this.otherSE set by factory
28821           }
28822
28823           _createClass(SweepEvent, [{
28824             key: "link",
28825             value: function link(other) {
28826               if (other.point === this.point) {
28827                 throw new Error('Tried to link already linked events');
28828               }
28829
28830               var otherEvents = other.point.events;
28831
28832               for (var i = 0, iMax = otherEvents.length; i < iMax; i++) {
28833                 var evt = otherEvents[i];
28834                 this.point.events.push(evt);
28835                 evt.point = this.point;
28836               }
28837
28838               this.checkForConsuming();
28839             }
28840             /* Do a pass over our linked events and check to see if any pair
28841              * of segments match, and should be consumed. */
28842
28843           }, {
28844             key: "checkForConsuming",
28845             value: function checkForConsuming() {
28846               // FIXME: The loops in this method run O(n^2) => no good.
28847               //        Maintain little ordered sweep event trees?
28848               //        Can we maintaining an ordering that avoids the need
28849               //        for the re-sorting with getLeftmostComparator in geom-out?
28850               // Compare each pair of events to see if other events also match
28851               var numEvents = this.point.events.length;
28852
28853               for (var i = 0; i < numEvents; i++) {
28854                 var evt1 = this.point.events[i];
28855                 if (evt1.segment.consumedBy !== undefined) continue;
28856
28857                 for (var j = i + 1; j < numEvents; j++) {
28858                   var evt2 = this.point.events[j];
28859                   if (evt2.consumedBy !== undefined) continue;
28860                   if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
28861                   evt1.segment.consume(evt2.segment);
28862                 }
28863               }
28864             }
28865           }, {
28866             key: "getAvailableLinkedEvents",
28867             value: function getAvailableLinkedEvents() {
28868               // point.events is always of length 2 or greater
28869               var events = [];
28870
28871               for (var i = 0, iMax = this.point.events.length; i < iMax; i++) {
28872                 var evt = this.point.events[i];
28873
28874                 if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
28875                   events.push(evt);
28876                 }
28877               }
28878
28879               return events;
28880             }
28881             /**
28882              * Returns a comparator function for sorting linked events that will
28883              * favor the event that will give us the smallest left-side angle.
28884              * All ring construction starts as low as possible heading to the right,
28885              * so by always turning left as sharp as possible we'll get polygons
28886              * without uncessary loops & holes.
28887              *
28888              * The comparator function has a compute cache such that it avoids
28889              * re-computing already-computed values.
28890              */
28891
28892           }, {
28893             key: "getLeftmostComparator",
28894             value: function getLeftmostComparator(baseEvent) {
28895               var _this = this;
28896
28897               var cache = new Map();
28898
28899               var fillCache = function fillCache(linkedEvent) {
28900                 var nextEvent = linkedEvent.otherSE;
28901                 cache.set(linkedEvent, {
28902                   sine: sineOfAngle(_this.point, baseEvent.point, nextEvent.point),
28903                   cosine: cosineOfAngle(_this.point, baseEvent.point, nextEvent.point)
28904                 });
28905               };
28906
28907               return function (a, b) {
28908                 if (!cache.has(a)) fillCache(a);
28909                 if (!cache.has(b)) fillCache(b);
28910
28911                 var _cache$get = cache.get(a),
28912                     asine = _cache$get.sine,
28913                     acosine = _cache$get.cosine;
28914
28915                 var _cache$get2 = cache.get(b),
28916                     bsine = _cache$get2.sine,
28917                     bcosine = _cache$get2.cosine; // both on or above x-axis
28918
28919
28920                 if (asine >= 0 && bsine >= 0) {
28921                   if (acosine < bcosine) return 1;
28922                   if (acosine > bcosine) return -1;
28923                   return 0;
28924                 } // both below x-axis
28925
28926
28927                 if (asine < 0 && bsine < 0) {
28928                   if (acosine < bcosine) return -1;
28929                   if (acosine > bcosine) return 1;
28930                   return 0;
28931                 } // one above x-axis, one below
28932
28933
28934                 if (bsine < asine) return -1;
28935                 if (bsine > asine) return 1;
28936                 return 0;
28937               };
28938             }
28939           }]);
28940
28941           return SweepEvent;
28942         }(); // segments and sweep events when all else is identical
28943
28944
28945         var segmentId = 0;
28946
28947         var Segment = /*#__PURE__*/function () {
28948           _createClass(Segment, null, [{
28949             key: "compare",
28950
28951             /* This compare() function is for ordering segments in the sweep
28952              * line tree, and does so according to the following criteria:
28953              *
28954              * Consider the vertical line that lies an infinestimal step to the
28955              * right of the right-more of the two left endpoints of the input
28956              * segments. Imagine slowly moving a point up from negative infinity
28957              * in the increasing y direction. Which of the two segments will that
28958              * point intersect first? That segment comes 'before' the other one.
28959              *
28960              * If neither segment would be intersected by such a line, (if one
28961              * or more of the segments are vertical) then the line to be considered
28962              * is directly on the right-more of the two left inputs.
28963              */
28964             value: function compare(a, b) {
28965               var alx = a.leftSE.point.x;
28966               var blx = b.leftSE.point.x;
28967               var arx = a.rightSE.point.x;
28968               var brx = b.rightSE.point.x; // check if they're even in the same vertical plane
28969
28970               if (brx < alx) return 1;
28971               if (arx < blx) return -1;
28972               var aly = a.leftSE.point.y;
28973               var bly = b.leftSE.point.y;
28974               var ary = a.rightSE.point.y;
28975               var bry = b.rightSE.point.y; // is left endpoint of segment B the right-more?
28976
28977               if (alx < blx) {
28978                 // are the two segments in the same horizontal plane?
28979                 if (bly < aly && bly < ary) return 1;
28980                 if (bly > aly && bly > ary) return -1; // is the B left endpoint colinear to segment A?
28981
28982                 var aCmpBLeft = a.comparePoint(b.leftSE.point);
28983                 if (aCmpBLeft < 0) return 1;
28984                 if (aCmpBLeft > 0) return -1; // is the A right endpoint colinear to segment B ?
28985
28986                 var bCmpARight = b.comparePoint(a.rightSE.point);
28987                 if (bCmpARight !== 0) return bCmpARight; // colinear segments, consider the one with left-more
28988                 // left endpoint to be first (arbitrary?)
28989
28990                 return -1;
28991               } // is left endpoint of segment A the right-more?
28992
28993
28994               if (alx > blx) {
28995                 if (aly < bly && aly < bry) return -1;
28996                 if (aly > bly && aly > bry) return 1; // is the A left endpoint colinear to segment B?
28997
28998                 var bCmpALeft = b.comparePoint(a.leftSE.point);
28999                 if (bCmpALeft !== 0) return bCmpALeft; // is the B right endpoint colinear to segment A?
29000
29001                 var aCmpBRight = a.comparePoint(b.rightSE.point);
29002                 if (aCmpBRight < 0) return 1;
29003                 if (aCmpBRight > 0) return -1; // colinear segments, consider the one with left-more
29004                 // left endpoint to be first (arbitrary?)
29005
29006                 return 1;
29007               } // if we get here, the two left endpoints are in the same
29008               // vertical plane, ie alx === blx
29009               // consider the lower left-endpoint to come first
29010
29011
29012               if (aly < bly) return -1;
29013               if (aly > bly) return 1; // left endpoints are identical
29014               // check for colinearity by using the left-more right endpoint
29015               // is the A right endpoint more left-more?
29016
29017               if (arx < brx) {
29018                 var _bCmpARight = b.comparePoint(a.rightSE.point);
29019
29020                 if (_bCmpARight !== 0) return _bCmpARight;
29021               } // is the B right endpoint more left-more?
29022
29023
29024               if (arx > brx) {
29025                 var _aCmpBRight = a.comparePoint(b.rightSE.point);
29026
29027                 if (_aCmpBRight < 0) return 1;
29028                 if (_aCmpBRight > 0) return -1;
29029               }
29030
29031               if (arx !== brx) {
29032                 // are these two [almost] vertical segments with opposite orientation?
29033                 // if so, the one with the lower right endpoint comes first
29034                 var ay = ary - aly;
29035                 var ax = arx - alx;
29036                 var by = bry - bly;
29037                 var bx = brx - blx;
29038                 if (ay > ax && by < bx) return 1;
29039                 if (ay < ax && by > bx) return -1;
29040               } // we have colinear segments with matching orientation
29041               // consider the one with more left-more right endpoint to be first
29042
29043
29044               if (arx > brx) return 1;
29045               if (arx < brx) return -1; // if we get here, two two right endpoints are in the same
29046               // vertical plane, ie arx === brx
29047               // consider the lower right-endpoint to come first
29048
29049               if (ary < bry) return -1;
29050               if (ary > bry) return 1; // right endpoints identical as well, so the segments are idential
29051               // fall back on creation order as consistent tie-breaker
29052
29053               if (a.id < b.id) return -1;
29054               if (a.id > b.id) return 1; // identical segment, ie a === b
29055
29056               return 0;
29057             }
29058             /* Warning: a reference to ringWindings input will be stored,
29059              *  and possibly will be later modified */
29060
29061           }]);
29062
29063           function Segment(leftSE, rightSE, rings, windings) {
29064             _classCallCheck(this, Segment);
29065
29066             this.id = ++segmentId;
29067             this.leftSE = leftSE;
29068             leftSE.segment = this;
29069             leftSE.otherSE = rightSE;
29070             this.rightSE = rightSE;
29071             rightSE.segment = this;
29072             rightSE.otherSE = leftSE;
29073             this.rings = rings;
29074             this.windings = windings; // left unset for performance, set later in algorithm
29075             // this.ringOut, this.consumedBy, this.prev
29076           }
29077
29078           _createClass(Segment, [{
29079             key: "replaceRightSE",
29080
29081             /* When a segment is split, the rightSE is replaced with a new sweep event */
29082             value: function replaceRightSE(newRightSE) {
29083               this.rightSE = newRightSE;
29084               this.rightSE.segment = this;
29085               this.rightSE.otherSE = this.leftSE;
29086               this.leftSE.otherSE = this.rightSE;
29087             }
29088           }, {
29089             key: "bbox",
29090             value: function bbox() {
29091               var y1 = this.leftSE.point.y;
29092               var y2 = this.rightSE.point.y;
29093               return {
29094                 ll: {
29095                   x: this.leftSE.point.x,
29096                   y: y1 < y2 ? y1 : y2
29097                 },
29098                 ur: {
29099                   x: this.rightSE.point.x,
29100                   y: y1 > y2 ? y1 : y2
29101                 }
29102               };
29103             }
29104             /* A vector from the left point to the right */
29105
29106           }, {
29107             key: "vector",
29108             value: function vector() {
29109               return {
29110                 x: this.rightSE.point.x - this.leftSE.point.x,
29111                 y: this.rightSE.point.y - this.leftSE.point.y
29112               };
29113             }
29114           }, {
29115             key: "isAnEndpoint",
29116             value: function isAnEndpoint(pt) {
29117               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;
29118             }
29119             /* Compare this segment with a point.
29120              *
29121              * A point P is considered to be colinear to a segment if there
29122              * exists a distance D such that if we travel along the segment
29123              * from one * endpoint towards the other a distance D, we find
29124              * ourselves at point P.
29125              *
29126              * Return value indicates:
29127              *
29128              *   1: point lies above the segment (to the left of vertical)
29129              *   0: point is colinear to segment
29130              *  -1: point lies below the segment (to the right of vertical)
29131              */
29132
29133           }, {
29134             key: "comparePoint",
29135             value: function comparePoint(point) {
29136               if (this.isAnEndpoint(point)) return 0;
29137               var lPt = this.leftSE.point;
29138               var rPt = this.rightSE.point;
29139               var v = this.vector(); // Exactly vertical segments.
29140
29141               if (lPt.x === rPt.x) {
29142                 if (point.x === lPt.x) return 0;
29143                 return point.x < lPt.x ? 1 : -1;
29144               } // Nearly vertical segments with an intersection.
29145               // Check to see where a point on the line with matching Y coordinate is.
29146
29147
29148               var yDist = (point.y - lPt.y) / v.y;
29149               var xFromYDist = lPt.x + yDist * v.x;
29150               if (point.x === xFromYDist) return 0; // General case.
29151               // Check to see where a point on the line with matching X coordinate is.
29152
29153               var xDist = (point.x - lPt.x) / v.x;
29154               var yFromXDist = lPt.y + xDist * v.y;
29155               if (point.y === yFromXDist) return 0;
29156               return point.y < yFromXDist ? -1 : 1;
29157             }
29158             /**
29159              * Given another segment, returns the first non-trivial intersection
29160              * between the two segments (in terms of sweep line ordering), if it exists.
29161              *
29162              * A 'non-trivial' intersection is one that will cause one or both of the
29163              * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
29164              *
29165              *   * endpoint of segA with endpoint of segB --> trivial
29166              *   * endpoint of segA with point along segB --> non-trivial
29167              *   * endpoint of segB with point along segA --> non-trivial
29168              *   * point along segA with point along segB --> non-trivial
29169              *
29170              * If no non-trivial intersection exists, return null
29171              * Else, return null.
29172              */
29173
29174           }, {
29175             key: "getIntersection",
29176             value: function getIntersection(other) {
29177               // If bboxes don't overlap, there can't be any intersections
29178               var tBbox = this.bbox();
29179               var oBbox = other.bbox();
29180               var bboxOverlap = getBboxOverlap(tBbox, oBbox);
29181               if (bboxOverlap === null) return null; // We first check to see if the endpoints can be considered intersections.
29182               // This will 'snap' intersections to endpoints if possible, and will
29183               // handle cases of colinearity.
29184
29185               var tlp = this.leftSE.point;
29186               var trp = this.rightSE.point;
29187               var olp = other.leftSE.point;
29188               var orp = other.rightSE.point; // does each endpoint touch the other segment?
29189               // note that we restrict the 'touching' definition to only allow segments
29190               // to touch endpoints that lie forward from where we are in the sweep line pass
29191
29192               var touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
29193               var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
29194               var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
29195               var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0; // do left endpoints match?
29196
29197               if (touchesThisLSE && touchesOtherLSE) {
29198                 // these two cases are for colinear segments with matching left
29199                 // endpoints, and one segment being longer than the other
29200                 if (touchesThisRSE && !touchesOtherRSE) return trp;
29201                 if (!touchesThisRSE && touchesOtherRSE) return orp; // either the two segments match exactly (two trival intersections)
29202                 // or just on their left endpoint (one trivial intersection
29203
29204                 return null;
29205               } // does this left endpoint matches (other doesn't)
29206
29207
29208               if (touchesThisLSE) {
29209                 // check for segments that just intersect on opposing endpoints
29210                 if (touchesOtherRSE) {
29211                   if (tlp.x === orp.x && tlp.y === orp.y) return null;
29212                 } // t-intersection on left endpoint
29213
29214
29215                 return tlp;
29216               } // does other left endpoint matches (this doesn't)
29217
29218
29219               if (touchesOtherLSE) {
29220                 // check for segments that just intersect on opposing endpoints
29221                 if (touchesThisRSE) {
29222                   if (trp.x === olp.x && trp.y === olp.y) return null;
29223                 } // t-intersection on left endpoint
29224
29225
29226                 return olp;
29227               } // trivial intersection on right endpoints
29228
29229
29230               if (touchesThisRSE && touchesOtherRSE) return null; // t-intersections on just one right endpoint
29231
29232               if (touchesThisRSE) return trp;
29233               if (touchesOtherRSE) return orp; // None of our endpoints intersect. Look for a general intersection between
29234               // infinite lines laid over the segments
29235
29236               var pt = intersection(tlp, this.vector(), olp, other.vector()); // are the segments parrallel? Note that if they were colinear with overlap,
29237               // they would have an endpoint intersection and that case was already handled above
29238
29239               if (pt === null) return null; // is the intersection found between the lines not on the segments?
29240
29241               if (!isInBbox(bboxOverlap, pt)) return null; // round the the computed point if needed
29242
29243               return rounder.round(pt.x, pt.y);
29244             }
29245             /**
29246              * Split the given segment into multiple segments on the given points.
29247              *  * Each existing segment will retain its leftSE and a new rightSE will be
29248              *    generated for it.
29249              *  * A new segment will be generated which will adopt the original segment's
29250              *    rightSE, and a new leftSE will be generated for it.
29251              *  * If there are more than two points given to split on, new segments
29252              *    in the middle will be generated with new leftSE and rightSE's.
29253              *  * An array of the newly generated SweepEvents will be returned.
29254              *
29255              * Warning: input array of points is modified
29256              */
29257
29258           }, {
29259             key: "split",
29260             value: function split(point) {
29261               var newEvents = [];
29262               var alreadyLinked = point.events !== undefined;
29263               var newLeftSE = new SweepEvent(point, true);
29264               var newRightSE = new SweepEvent(point, false);
29265               var oldRightSE = this.rightSE;
29266               this.replaceRightSE(newRightSE);
29267               newEvents.push(newRightSE);
29268               newEvents.push(newLeftSE);
29269               var newSeg = new Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice()); // when splitting a nearly vertical downward-facing segment,
29270               // sometimes one of the resulting new segments is vertical, in which
29271               // case its left and right events may need to be swapped
29272
29273               if (SweepEvent.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
29274                 newSeg.swapEvents();
29275               }
29276
29277               if (SweepEvent.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
29278                 this.swapEvents();
29279               } // in the point we just used to create new sweep events with was already
29280               // linked to other events, we need to check if either of the affected
29281               // segments should be consumed
29282
29283
29284               if (alreadyLinked) {
29285                 newLeftSE.checkForConsuming();
29286                 newRightSE.checkForConsuming();
29287               }
29288
29289               return newEvents;
29290             }
29291             /* Swap which event is left and right */
29292
29293           }, {
29294             key: "swapEvents",
29295             value: function swapEvents() {
29296               var tmpEvt = this.rightSE;
29297               this.rightSE = this.leftSE;
29298               this.leftSE = tmpEvt;
29299               this.leftSE.isLeft = true;
29300               this.rightSE.isLeft = false;
29301
29302               for (var i = 0, iMax = this.windings.length; i < iMax; i++) {
29303                 this.windings[i] *= -1;
29304               }
29305             }
29306             /* Consume another segment. We take their rings under our wing
29307              * and mark them as consumed. Use for perfectly overlapping segments */
29308
29309           }, {
29310             key: "consume",
29311             value: function consume(other) {
29312               var consumer = this;
29313               var consumee = other;
29314
29315               while (consumer.consumedBy) {
29316                 consumer = consumer.consumedBy;
29317               }
29318
29319               while (consumee.consumedBy) {
29320                 consumee = consumee.consumedBy;
29321               }
29322
29323               var cmp = Segment.compare(consumer, consumee);
29324               if (cmp === 0) return; // already consumed
29325               // the winner of the consumption is the earlier segment
29326               // according to sweep line ordering
29327
29328               if (cmp > 0) {
29329                 var tmp = consumer;
29330                 consumer = consumee;
29331                 consumee = tmp;
29332               } // make sure a segment doesn't consume it's prev
29333
29334
29335               if (consumer.prev === consumee) {
29336                 var _tmp = consumer;
29337                 consumer = consumee;
29338                 consumee = _tmp;
29339               }
29340
29341               for (var i = 0, iMax = consumee.rings.length; i < iMax; i++) {
29342                 var ring = consumee.rings[i];
29343                 var winding = consumee.windings[i];
29344                 var index = consumer.rings.indexOf(ring);
29345
29346                 if (index === -1) {
29347                   consumer.rings.push(ring);
29348                   consumer.windings.push(winding);
29349                 } else consumer.windings[index] += winding;
29350               }
29351
29352               consumee.rings = null;
29353               consumee.windings = null;
29354               consumee.consumedBy = consumer; // mark sweep events consumed as to maintain ordering in sweep event queue
29355
29356               consumee.leftSE.consumedBy = consumer.leftSE;
29357               consumee.rightSE.consumedBy = consumer.rightSE;
29358             }
29359             /* The first segment previous segment chain that is in the result */
29360
29361           }, {
29362             key: "prevInResult",
29363             value: function prevInResult() {
29364               if (this._prevInResult !== undefined) return this._prevInResult;
29365               if (!this.prev) this._prevInResult = null;else if (this.prev.isInResult()) this._prevInResult = this.prev;else this._prevInResult = this.prev.prevInResult();
29366               return this._prevInResult;
29367             }
29368           }, {
29369             key: "beforeState",
29370             value: function beforeState() {
29371               if (this._beforeState !== undefined) return this._beforeState;
29372               if (!this.prev) this._beforeState = {
29373                 rings: [],
29374                 windings: [],
29375                 multiPolys: []
29376               };else {
29377                 var seg = this.prev.consumedBy || this.prev;
29378                 this._beforeState = seg.afterState();
29379               }
29380               return this._beforeState;
29381             }
29382           }, {
29383             key: "afterState",
29384             value: function afterState() {
29385               if (this._afterState !== undefined) return this._afterState;
29386               var beforeState = this.beforeState();
29387               this._afterState = {
29388                 rings: beforeState.rings.slice(0),
29389                 windings: beforeState.windings.slice(0),
29390                 multiPolys: []
29391               };
29392               var ringsAfter = this._afterState.rings;
29393               var windingsAfter = this._afterState.windings;
29394               var mpsAfter = this._afterState.multiPolys; // calculate ringsAfter, windingsAfter
29395
29396               for (var i = 0, iMax = this.rings.length; i < iMax; i++) {
29397                 var ring = this.rings[i];
29398                 var winding = this.windings[i];
29399                 var index = ringsAfter.indexOf(ring);
29400
29401                 if (index === -1) {
29402                   ringsAfter.push(ring);
29403                   windingsAfter.push(winding);
29404                 } else windingsAfter[index] += winding;
29405               } // calcualte polysAfter
29406
29407
29408               var polysAfter = [];
29409               var polysExclude = [];
29410
29411               for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
29412                 if (windingsAfter[_i] === 0) continue; // non-zero rule
29413
29414                 var _ring = ringsAfter[_i];
29415                 var poly = _ring.poly;
29416                 if (polysExclude.indexOf(poly) !== -1) continue;
29417                 if (_ring.isExterior) polysAfter.push(poly);else {
29418                   if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
29419
29420                   var _index = polysAfter.indexOf(_ring.poly);
29421
29422                   if (_index !== -1) polysAfter.splice(_index, 1);
29423                 }
29424               } // calculate multiPolysAfter
29425
29426
29427               for (var _i2 = 0, _iMax2 = polysAfter.length; _i2 < _iMax2; _i2++) {
29428                 var mp = polysAfter[_i2].multiPoly;
29429                 if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
29430               }
29431
29432               return this._afterState;
29433             }
29434             /* Is this segment part of the final result? */
29435
29436           }, {
29437             key: "isInResult",
29438             value: function isInResult() {
29439               // if we've been consumed, we're not in the result
29440               if (this.consumedBy) return false;
29441               if (this._isInResult !== undefined) return this._isInResult;
29442               var mpsBefore = this.beforeState().multiPolys;
29443               var mpsAfter = this.afterState().multiPolys;
29444
29445               switch (operation.type) {
29446                 case 'union':
29447                   {
29448                     // UNION - included iff:
29449                     //  * On one side of us there is 0 poly interiors AND
29450                     //  * On the other side there is 1 or more.
29451                     var noBefores = mpsBefore.length === 0;
29452                     var noAfters = mpsAfter.length === 0;
29453                     this._isInResult = noBefores !== noAfters;
29454                     break;
29455                   }
29456
29457                 case 'intersection':
29458                   {
29459                     // INTERSECTION - included iff:
29460                     //  * on one side of us all multipolys are rep. with poly interiors AND
29461                     //  * on the other side of us, not all multipolys are repsented
29462                     //    with poly interiors
29463                     var least;
29464                     var most;
29465
29466                     if (mpsBefore.length < mpsAfter.length) {
29467                       least = mpsBefore.length;
29468                       most = mpsAfter.length;
29469                     } else {
29470                       least = mpsAfter.length;
29471                       most = mpsBefore.length;
29472                     }
29473
29474                     this._isInResult = most === operation.numMultiPolys && least < most;
29475                     break;
29476                   }
29477
29478                 case 'xor':
29479                   {
29480                     // XOR - included iff:
29481                     //  * the difference between the number of multipolys represented
29482                     //    with poly interiors on our two sides is an odd number
29483                     var diff = Math.abs(mpsBefore.length - mpsAfter.length);
29484                     this._isInResult = diff % 2 === 1;
29485                     break;
29486                   }
29487
29488                 case 'difference':
29489                   {
29490                     // DIFFERENCE included iff:
29491                     //  * on exactly one side, we have just the subject
29492                     var isJustSubject = function isJustSubject(mps) {
29493                       return mps.length === 1 && mps[0].isSubject;
29494                     };
29495
29496                     this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
29497                     break;
29498                   }
29499
29500                 default:
29501                   throw new Error("Unrecognized operation type found ".concat(operation.type));
29502               }
29503
29504               return this._isInResult;
29505             }
29506           }], [{
29507             key: "fromRing",
29508             value: function fromRing(pt1, pt2, ring) {
29509               var leftPt, rightPt, winding; // ordering the two points according to sweep line ordering
29510
29511               var cmpPts = SweepEvent.comparePoints(pt1, pt2);
29512
29513               if (cmpPts < 0) {
29514                 leftPt = pt1;
29515                 rightPt = pt2;
29516                 winding = 1;
29517               } else if (cmpPts > 0) {
29518                 leftPt = pt2;
29519                 rightPt = pt1;
29520                 winding = -1;
29521               } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
29522
29523               var leftSE = new SweepEvent(leftPt, true);
29524               var rightSE = new SweepEvent(rightPt, false);
29525               return new Segment(leftSE, rightSE, [ring], [winding]);
29526             }
29527           }]);
29528
29529           return Segment;
29530         }();
29531
29532         var RingIn = /*#__PURE__*/function () {
29533           function RingIn(geomRing, poly, isExterior) {
29534             _classCallCheck(this, RingIn);
29535
29536             if (!Array.isArray(geomRing) || geomRing.length === 0) {
29537               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
29538             }
29539
29540             this.poly = poly;
29541             this.isExterior = isExterior;
29542             this.segments = [];
29543
29544             if (typeof geomRing[0][0] !== 'number' || typeof geomRing[0][1] !== 'number') {
29545               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
29546             }
29547
29548             var firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
29549             this.bbox = {
29550               ll: {
29551                 x: firstPoint.x,
29552                 y: firstPoint.y
29553               },
29554               ur: {
29555                 x: firstPoint.x,
29556                 y: firstPoint.y
29557               }
29558             };
29559             var prevPoint = firstPoint;
29560
29561             for (var i = 1, iMax = geomRing.length; i < iMax; i++) {
29562               if (typeof geomRing[i][0] !== 'number' || typeof geomRing[i][1] !== 'number') {
29563                 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
29564               }
29565
29566               var point = rounder.round(geomRing[i][0], geomRing[i][1]); // skip repeated points
29567
29568               if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
29569               this.segments.push(Segment.fromRing(prevPoint, point, this));
29570               if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
29571               if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
29572               if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
29573               if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
29574               prevPoint = point;
29575             } // add segment from last to first if last is not the same as first
29576
29577
29578             if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
29579               this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
29580             }
29581           }
29582
29583           _createClass(RingIn, [{
29584             key: "getSweepEvents",
29585             value: function getSweepEvents() {
29586               var sweepEvents = [];
29587
29588               for (var i = 0, iMax = this.segments.length; i < iMax; i++) {
29589                 var segment = this.segments[i];
29590                 sweepEvents.push(segment.leftSE);
29591                 sweepEvents.push(segment.rightSE);
29592               }
29593
29594               return sweepEvents;
29595             }
29596           }]);
29597
29598           return RingIn;
29599         }();
29600
29601         var PolyIn = /*#__PURE__*/function () {
29602           function PolyIn(geomPoly, multiPoly) {
29603             _classCallCheck(this, PolyIn);
29604
29605             if (!Array.isArray(geomPoly)) {
29606               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
29607             }
29608
29609             this.exteriorRing = new RingIn(geomPoly[0], this, true); // copy by value
29610
29611             this.bbox = {
29612               ll: {
29613                 x: this.exteriorRing.bbox.ll.x,
29614                 y: this.exteriorRing.bbox.ll.y
29615               },
29616               ur: {
29617                 x: this.exteriorRing.bbox.ur.x,
29618                 y: this.exteriorRing.bbox.ur.y
29619               }
29620             };
29621             this.interiorRings = [];
29622
29623             for (var i = 1, iMax = geomPoly.length; i < iMax; i++) {
29624               var ring = new RingIn(geomPoly[i], this, false);
29625               if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
29626               if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
29627               if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
29628               if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
29629               this.interiorRings.push(ring);
29630             }
29631
29632             this.multiPoly = multiPoly;
29633           }
29634
29635           _createClass(PolyIn, [{
29636             key: "getSweepEvents",
29637             value: function getSweepEvents() {
29638               var sweepEvents = this.exteriorRing.getSweepEvents();
29639
29640               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
29641                 var ringSweepEvents = this.interiorRings[i].getSweepEvents();
29642
29643                 for (var j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
29644                   sweepEvents.push(ringSweepEvents[j]);
29645                 }
29646               }
29647
29648               return sweepEvents;
29649             }
29650           }]);
29651
29652           return PolyIn;
29653         }();
29654
29655         var MultiPolyIn = /*#__PURE__*/function () {
29656           function MultiPolyIn(geom, isSubject) {
29657             _classCallCheck(this, MultiPolyIn);
29658
29659             if (!Array.isArray(geom)) {
29660               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
29661             }
29662
29663             try {
29664               // if the input looks like a polygon, convert it to a multipolygon
29665               if (typeof geom[0][0][0] === 'number') geom = [geom];
29666             } catch (ex) {// The input is either malformed or has empty arrays.
29667               // In either case, it will be handled later on.
29668             }
29669
29670             this.polys = [];
29671             this.bbox = {
29672               ll: {
29673                 x: Number.POSITIVE_INFINITY,
29674                 y: Number.POSITIVE_INFINITY
29675               },
29676               ur: {
29677                 x: Number.NEGATIVE_INFINITY,
29678                 y: Number.NEGATIVE_INFINITY
29679               }
29680             };
29681
29682             for (var i = 0, iMax = geom.length; i < iMax; i++) {
29683               var poly = new PolyIn(geom[i], this);
29684               if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
29685               if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
29686               if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
29687               if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
29688               this.polys.push(poly);
29689             }
29690
29691             this.isSubject = isSubject;
29692           }
29693
29694           _createClass(MultiPolyIn, [{
29695             key: "getSweepEvents",
29696             value: function getSweepEvents() {
29697               var sweepEvents = [];
29698
29699               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
29700                 var polySweepEvents = this.polys[i].getSweepEvents();
29701
29702                 for (var j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
29703                   sweepEvents.push(polySweepEvents[j]);
29704                 }
29705               }
29706
29707               return sweepEvents;
29708             }
29709           }]);
29710
29711           return MultiPolyIn;
29712         }();
29713
29714         var RingOut = /*#__PURE__*/function () {
29715           _createClass(RingOut, null, [{
29716             key: "factory",
29717
29718             /* Given the segments from the sweep line pass, compute & return a series
29719              * of closed rings from all the segments marked to be part of the result */
29720             value: function factory(allSegments) {
29721               var ringsOut = [];
29722
29723               for (var i = 0, iMax = allSegments.length; i < iMax; i++) {
29724                 var segment = allSegments[i];
29725                 if (!segment.isInResult() || segment.ringOut) continue;
29726                 var prevEvent = null;
29727                 var event = segment.leftSE;
29728                 var nextEvent = segment.rightSE;
29729                 var events = [event];
29730                 var startingPoint = event.point;
29731                 var intersectionLEs = [];
29732                 /* Walk the chain of linked events to form a closed ring */
29733
29734                 while (true) {
29735                   prevEvent = event;
29736                   event = nextEvent;
29737                   events.push(event);
29738                   /* Is the ring complete? */
29739
29740                   if (event.point === startingPoint) break;
29741
29742                   while (true) {
29743                     var availableLEs = event.getAvailableLinkedEvents();
29744                     /* Did we hit a dead end? This shouldn't happen. Indicates some earlier
29745                      * part of the algorithm malfunctioned... please file a bug report. */
29746
29747                     if (availableLEs.length === 0) {
29748                       var firstPt = events[0].point;
29749                       var lastPt = events[events.length - 1].point;
29750                       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, "]."));
29751                     }
29752                     /* Only one way to go, so cotinue on the path */
29753
29754
29755                     if (availableLEs.length === 1) {
29756                       nextEvent = availableLEs[0].otherSE;
29757                       break;
29758                     }
29759                     /* We must have an intersection. Check for a completed loop */
29760
29761
29762                     var indexLE = null;
29763
29764                     for (var j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
29765                       if (intersectionLEs[j].point === event.point) {
29766                         indexLE = j;
29767                         break;
29768                       }
29769                     }
29770                     /* Found a completed loop. Cut that off and make a ring */
29771
29772
29773                     if (indexLE !== null) {
29774                       var intersectionLE = intersectionLEs.splice(indexLE)[0];
29775                       var ringEvents = events.splice(intersectionLE.index);
29776                       ringEvents.unshift(ringEvents[0].otherSE);
29777                       ringsOut.push(new RingOut(ringEvents.reverse()));
29778                       continue;
29779                     }
29780                     /* register the intersection */
29781
29782
29783                     intersectionLEs.push({
29784                       index: events.length,
29785                       point: event.point
29786                     });
29787                     /* Choose the left-most option to continue the walk */
29788
29789                     var comparator = event.getLeftmostComparator(prevEvent);
29790                     nextEvent = availableLEs.sort(comparator)[0].otherSE;
29791                     break;
29792                   }
29793                 }
29794
29795                 ringsOut.push(new RingOut(events));
29796               }
29797
29798               return ringsOut;
29799             }
29800           }]);
29801
29802           function RingOut(events) {
29803             _classCallCheck(this, RingOut);
29804
29805             this.events = events;
29806
29807             for (var i = 0, iMax = events.length; i < iMax; i++) {
29808               events[i].segment.ringOut = this;
29809             }
29810
29811             this.poly = null;
29812           }
29813
29814           _createClass(RingOut, [{
29815             key: "getGeom",
29816             value: function getGeom() {
29817               // Remove superfluous points (ie extra points along a straight line),
29818               var prevPt = this.events[0].point;
29819               var points = [prevPt];
29820
29821               for (var i = 1, iMax = this.events.length - 1; i < iMax; i++) {
29822                 var _pt = this.events[i].point;
29823                 var _nextPt = this.events[i + 1].point;
29824                 if (compareVectorAngles(_pt, prevPt, _nextPt) === 0) continue;
29825                 points.push(_pt);
29826                 prevPt = _pt;
29827               } // ring was all (within rounding error of angle calc) colinear points
29828
29829
29830               if (points.length === 1) return null; // check if the starting point is necessary
29831
29832               var pt = points[0];
29833               var nextPt = points[1];
29834               if (compareVectorAngles(pt, prevPt, nextPt) === 0) points.shift();
29835               points.push(points[0]);
29836               var step = this.isExteriorRing() ? 1 : -1;
29837               var iStart = this.isExteriorRing() ? 0 : points.length - 1;
29838               var iEnd = this.isExteriorRing() ? points.length : -1;
29839               var orderedPoints = [];
29840
29841               for (var _i = iStart; _i != iEnd; _i += step) {
29842                 orderedPoints.push([points[_i].x, points[_i].y]);
29843               }
29844
29845               return orderedPoints;
29846             }
29847           }, {
29848             key: "isExteriorRing",
29849             value: function isExteriorRing() {
29850               if (this._isExteriorRing === undefined) {
29851                 var enclosing = this.enclosingRing();
29852                 this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
29853               }
29854
29855               return this._isExteriorRing;
29856             }
29857           }, {
29858             key: "enclosingRing",
29859             value: function enclosingRing() {
29860               if (this._enclosingRing === undefined) {
29861                 this._enclosingRing = this._calcEnclosingRing();
29862               }
29863
29864               return this._enclosingRing;
29865             }
29866             /* Returns the ring that encloses this one, if any */
29867
29868           }, {
29869             key: "_calcEnclosingRing",
29870             value: function _calcEnclosingRing() {
29871               // start with the ealier sweep line event so that the prevSeg
29872               // chain doesn't lead us inside of a loop of ours
29873               var leftMostEvt = this.events[0];
29874
29875               for (var i = 1, iMax = this.events.length; i < iMax; i++) {
29876                 var evt = this.events[i];
29877                 if (SweepEvent.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
29878               }
29879
29880               var prevSeg = leftMostEvt.segment.prevInResult();
29881               var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
29882
29883               while (true) {
29884                 // no segment found, thus no ring can enclose us
29885                 if (!prevSeg) return null; // no segments below prev segment found, thus the ring of the prev
29886                 // segment must loop back around and enclose us
29887
29888                 if (!prevPrevSeg) return prevSeg.ringOut; // if the two segments are of different rings, the ring of the prev
29889                 // segment must either loop around us or the ring of the prev prev
29890                 // seg, which would make us and the ring of the prev peers
29891
29892                 if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
29893                   if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
29894                     return prevSeg.ringOut;
29895                   } else return prevSeg.ringOut.enclosingRing();
29896                 } // two segments are from the same ring, so this was a penisula
29897                 // of that ring. iterate downward, keep searching
29898
29899
29900                 prevSeg = prevPrevSeg.prevInResult();
29901                 prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
29902               }
29903             }
29904           }]);
29905
29906           return RingOut;
29907         }();
29908
29909         var PolyOut = /*#__PURE__*/function () {
29910           function PolyOut(exteriorRing) {
29911             _classCallCheck(this, PolyOut);
29912
29913             this.exteriorRing = exteriorRing;
29914             exteriorRing.poly = this;
29915             this.interiorRings = [];
29916           }
29917
29918           _createClass(PolyOut, [{
29919             key: "addInterior",
29920             value: function addInterior(ring) {
29921               this.interiorRings.push(ring);
29922               ring.poly = this;
29923             }
29924           }, {
29925             key: "getGeom",
29926             value: function getGeom() {
29927               var geom = [this.exteriorRing.getGeom()]; // exterior ring was all (within rounding error of angle calc) colinear points
29928
29929               if (geom[0] === null) return null;
29930
29931               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
29932                 var ringGeom = this.interiorRings[i].getGeom(); // interior ring was all (within rounding error of angle calc) colinear points
29933
29934                 if (ringGeom === null) continue;
29935                 geom.push(ringGeom);
29936               }
29937
29938               return geom;
29939             }
29940           }]);
29941
29942           return PolyOut;
29943         }();
29944
29945         var MultiPolyOut = /*#__PURE__*/function () {
29946           function MultiPolyOut(rings) {
29947             _classCallCheck(this, MultiPolyOut);
29948
29949             this.rings = rings;
29950             this.polys = this._composePolys(rings);
29951           }
29952
29953           _createClass(MultiPolyOut, [{
29954             key: "getGeom",
29955             value: function getGeom() {
29956               var geom = [];
29957
29958               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
29959                 var polyGeom = this.polys[i].getGeom(); // exterior ring was all (within rounding error of angle calc) colinear points
29960
29961                 if (polyGeom === null) continue;
29962                 geom.push(polyGeom);
29963               }
29964
29965               return geom;
29966             }
29967           }, {
29968             key: "_composePolys",
29969             value: function _composePolys(rings) {
29970               var polys = [];
29971
29972               for (var i = 0, iMax = rings.length; i < iMax; i++) {
29973                 var ring = rings[i];
29974                 if (ring.poly) continue;
29975                 if (ring.isExteriorRing()) polys.push(new PolyOut(ring));else {
29976                   var enclosingRing = ring.enclosingRing();
29977                   if (!enclosingRing.poly) polys.push(new PolyOut(enclosingRing));
29978                   enclosingRing.poly.addInterior(ring);
29979                 }
29980               }
29981
29982               return polys;
29983             }
29984           }]);
29985
29986           return MultiPolyOut;
29987         }();
29988         /**
29989          * NOTE:  We must be careful not to change any segments while
29990          *        they are in the SplayTree. AFAIK, there's no way to tell
29991          *        the tree to rebalance itself - thus before splitting
29992          *        a segment that's in the tree, we remove it from the tree,
29993          *        do the split, then re-insert it. (Even though splitting a
29994          *        segment *shouldn't* change its correct position in the
29995          *        sweep line tree, the reality is because of rounding errors,
29996          *        it sometimes does.)
29997          */
29998
29999
30000         var SweepLine = /*#__PURE__*/function () {
30001           function SweepLine(queue) {
30002             var comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
30003
30004             _classCallCheck(this, SweepLine);
30005
30006             this.queue = queue;
30007             this.tree = new Tree(comparator);
30008             this.segments = [];
30009           }
30010
30011           _createClass(SweepLine, [{
30012             key: "process",
30013             value: function process(event) {
30014               var segment = event.segment;
30015               var newEvents = []; // if we've already been consumed by another segment,
30016               // clean up our body parts and get out
30017
30018               if (event.consumedBy) {
30019                 if (event.isLeft) this.queue.remove(event.otherSE);else this.tree.remove(segment);
30020                 return newEvents;
30021               }
30022
30023               var node = event.isLeft ? this.tree.insert(segment) : this.tree.find(segment);
30024               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.');
30025               var prevNode = node;
30026               var nextNode = node;
30027               var prevSeg = undefined;
30028               var nextSeg = undefined; // skip consumed segments still in tree
30029
30030               while (prevSeg === undefined) {
30031                 prevNode = this.tree.prev(prevNode);
30032                 if (prevNode === null) prevSeg = null;else if (prevNode.key.consumedBy === undefined) prevSeg = prevNode.key;
30033               } // skip consumed segments still in tree
30034
30035
30036               while (nextSeg === undefined) {
30037                 nextNode = this.tree.next(nextNode);
30038                 if (nextNode === null) nextSeg = null;else if (nextNode.key.consumedBy === undefined) nextSeg = nextNode.key;
30039               }
30040
30041               if (event.isLeft) {
30042                 // Check for intersections against the previous segment in the sweep line
30043                 var prevMySplitter = null;
30044
30045                 if (prevSeg) {
30046                   var prevInter = prevSeg.getIntersection(segment);
30047
30048                   if (prevInter !== null) {
30049                     if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
30050
30051                     if (!prevSeg.isAnEndpoint(prevInter)) {
30052                       var newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
30053
30054                       for (var i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
30055                         newEvents.push(newEventsFromSplit[i]);
30056                       }
30057                     }
30058                   }
30059                 } // Check for intersections against the next segment in the sweep line
30060
30061
30062                 var nextMySplitter = null;
30063
30064                 if (nextSeg) {
30065                   var nextInter = nextSeg.getIntersection(segment);
30066
30067                   if (nextInter !== null) {
30068                     if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
30069
30070                     if (!nextSeg.isAnEndpoint(nextInter)) {
30071                       var _newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
30072
30073                       for (var _i = 0, _iMax = _newEventsFromSplit.length; _i < _iMax; _i++) {
30074                         newEvents.push(_newEventsFromSplit[_i]);
30075                       }
30076                     }
30077                   }
30078                 } // For simplicity, even if we find more than one intersection we only
30079                 // spilt on the 'earliest' (sweep-line style) of the intersections.
30080                 // The other intersection will be handled in a future process().
30081
30082
30083                 if (prevMySplitter !== null || nextMySplitter !== null) {
30084                   var mySplitter = null;
30085                   if (prevMySplitter === null) mySplitter = nextMySplitter;else if (nextMySplitter === null) mySplitter = prevMySplitter;else {
30086                     var cmpSplitters = SweepEvent.comparePoints(prevMySplitter, nextMySplitter);
30087                     mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
30088                   } // Rounding errors can cause changes in ordering,
30089                   // so remove afected segments and right sweep events before splitting
30090
30091                   this.queue.remove(segment.rightSE);
30092                   newEvents.push(segment.rightSE);
30093
30094                   var _newEventsFromSplit2 = segment.split(mySplitter);
30095
30096                   for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
30097                     newEvents.push(_newEventsFromSplit2[_i2]);
30098                   }
30099                 }
30100
30101                 if (newEvents.length > 0) {
30102                   // We found some intersections, so re-do the current event to
30103                   // make sure sweep line ordering is totally consistent for later
30104                   // use with the segment 'prev' pointers
30105                   this.tree.remove(segment);
30106                   newEvents.push(event);
30107                 } else {
30108                   // done with left event
30109                   this.segments.push(segment);
30110                   segment.prev = prevSeg;
30111                 }
30112               } else {
30113                 // event.isRight
30114                 // since we're about to be removed from the sweep line, check for
30115                 // intersections between our previous and next segments
30116                 if (prevSeg && nextSeg) {
30117                   var inter = prevSeg.getIntersection(nextSeg);
30118
30119                   if (inter !== null) {
30120                     if (!prevSeg.isAnEndpoint(inter)) {
30121                       var _newEventsFromSplit3 = this._splitSafely(prevSeg, inter);
30122
30123                       for (var _i3 = 0, _iMax3 = _newEventsFromSplit3.length; _i3 < _iMax3; _i3++) {
30124                         newEvents.push(_newEventsFromSplit3[_i3]);
30125                       }
30126                     }
30127
30128                     if (!nextSeg.isAnEndpoint(inter)) {
30129                       var _newEventsFromSplit4 = this._splitSafely(nextSeg, inter);
30130
30131                       for (var _i4 = 0, _iMax4 = _newEventsFromSplit4.length; _i4 < _iMax4; _i4++) {
30132                         newEvents.push(_newEventsFromSplit4[_i4]);
30133                       }
30134                     }
30135                   }
30136                 }
30137
30138                 this.tree.remove(segment);
30139               }
30140
30141               return newEvents;
30142             }
30143             /* Safely split a segment that is currently in the datastructures
30144              * IE - a segment other than the one that is currently being processed. */
30145
30146           }, {
30147             key: "_splitSafely",
30148             value: function _splitSafely(seg, pt) {
30149               // Rounding errors can cause changes in ordering,
30150               // so remove afected segments and right sweep events before splitting
30151               // removeNode() doesn't work, so have re-find the seg
30152               // https://github.com/w8r/splay-tree/pull/5
30153               this.tree.remove(seg);
30154               var rightSE = seg.rightSE;
30155               this.queue.remove(rightSE);
30156               var newEvents = seg.split(pt);
30157               newEvents.push(rightSE); // splitting can trigger consumption
30158
30159               if (seg.consumedBy === undefined) this.tree.insert(seg);
30160               return newEvents;
30161             }
30162           }]);
30163
30164           return SweepLine;
30165         }();
30166
30167         var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
30168         var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
30169
30170         var Operation = /*#__PURE__*/function () {
30171           function Operation() {
30172             _classCallCheck(this, Operation);
30173           }
30174
30175           _createClass(Operation, [{
30176             key: "run",
30177             value: function run(type, geom, moreGeoms) {
30178               operation.type = type;
30179               rounder.reset();
30180               /* Convert inputs to MultiPoly objects */
30181
30182               var multipolys = [new MultiPolyIn(geom, true)];
30183
30184               for (var i = 0, iMax = moreGeoms.length; i < iMax; i++) {
30185                 multipolys.push(new MultiPolyIn(moreGeoms[i], false));
30186               }
30187
30188               operation.numMultiPolys = multipolys.length;
30189               /* BBox optimization for difference operation
30190                * If the bbox of a multipolygon that's part of the clipping doesn't
30191                * intersect the bbox of the subject at all, we can just drop that
30192                * multiploygon. */
30193
30194               if (operation.type === 'difference') {
30195                 // in place removal
30196                 var subject = multipolys[0];
30197                 var _i = 1;
30198
30199                 while (_i < multipolys.length) {
30200                   if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null) _i++;else multipolys.splice(_i, 1);
30201                 }
30202               }
30203               /* BBox optimization for intersection operation
30204                * If we can find any pair of multipolygons whose bbox does not overlap,
30205                * then the result will be empty. */
30206
30207
30208               if (operation.type === 'intersection') {
30209                 // TODO: this is O(n^2) in number of polygons. By sorting the bboxes,
30210                 //       it could be optimized to O(n * ln(n))
30211                 for (var _i2 = 0, _iMax = multipolys.length; _i2 < _iMax; _i2++) {
30212                   var mpA = multipolys[_i2];
30213
30214                   for (var j = _i2 + 1, jMax = multipolys.length; j < jMax; j++) {
30215                     if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
30216                   }
30217                 }
30218               }
30219               /* Put segment endpoints in a priority queue */
30220
30221
30222               var queue = new Tree(SweepEvent.compare);
30223
30224               for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
30225                 var sweepEvents = multipolys[_i3].getSweepEvents();
30226
30227                 for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
30228                   queue.insert(sweepEvents[_j]);
30229
30230                   if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
30231                     // prevents an infinite loop, an otherwise common manifestation of bugs
30232                     throw new Error('Infinite loop when putting segment endpoints in a priority queue ' + '(queue size too big). Please file a bug report.');
30233                   }
30234                 }
30235               }
30236               /* Pass the sweep line over those endpoints */
30237
30238
30239               var sweepLine = new SweepLine(queue);
30240               var prevQueueSize = queue.size;
30241               var node = queue.pop();
30242
30243               while (node) {
30244                 var evt = node.key;
30245
30246                 if (queue.size === prevQueueSize) {
30247                   // prevents an infinite loop, an otherwise common manifestation of bugs
30248                   var seg = evt.segment;
30249                   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.');
30250                 }
30251
30252                 if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
30253                   // prevents an infinite loop, an otherwise common manifestation of bugs
30254                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(queue size too big). Please file a bug report.');
30255                 }
30256
30257                 if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
30258                   // prevents an infinite loop, an otherwise common manifestation of bugs
30259                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(too many sweep line segments). Please file a bug report.');
30260                 }
30261
30262                 var newEvents = sweepLine.process(evt);
30263
30264                 for (var _i4 = 0, _iMax3 = newEvents.length; _i4 < _iMax3; _i4++) {
30265                   var _evt = newEvents[_i4];
30266                   if (_evt.consumedBy === undefined) queue.insert(_evt);
30267                 }
30268
30269                 prevQueueSize = queue.size;
30270                 node = queue.pop();
30271               } // free some memory we don't need anymore
30272
30273
30274               rounder.reset();
30275               /* Collect and compile segments we're keeping into a multipolygon */
30276
30277               var ringsOut = RingOut.factory(sweepLine.segments);
30278               var result = new MultiPolyOut(ringsOut);
30279               return result.getGeom();
30280             }
30281           }]);
30282
30283           return Operation;
30284         }(); // singleton available by import
30285
30286
30287         var operation = new Operation();
30288
30289         var union = function union(geom) {
30290           for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
30291             moreGeoms[_key - 1] = arguments[_key];
30292           }
30293
30294           return operation.run('union', geom, moreGeoms);
30295         };
30296
30297         var intersection$1 = function intersection(geom) {
30298           for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
30299             moreGeoms[_key2 - 1] = arguments[_key2];
30300           }
30301
30302           return operation.run('intersection', geom, moreGeoms);
30303         };
30304
30305         var xor = function xor(geom) {
30306           for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
30307             moreGeoms[_key3 - 1] = arguments[_key3];
30308           }
30309
30310           return operation.run('xor', geom, moreGeoms);
30311         };
30312
30313         var difference = function difference(subjectGeom) {
30314           for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
30315             clippingGeoms[_key4 - 1] = arguments[_key4];
30316           }
30317
30318           return operation.run('difference', subjectGeom, clippingGeoms);
30319         };
30320
30321         var index = {
30322           union: union,
30323           intersection: intersection$1,
30324           xor: xor,
30325           difference: difference
30326         };
30327
30328         var geojsonPrecision = createCommonjsModule(function (module) {
30329           (function () {
30330             function parse(t, coordinatePrecision, extrasPrecision) {
30331               function point(p) {
30332                 return p.map(function (e, index) {
30333                   if (index < 2) {
30334                     return 1 * e.toFixed(coordinatePrecision);
30335                   } else {
30336                     return 1 * e.toFixed(extrasPrecision);
30337                   }
30338                 });
30339               }
30340
30341               function multi(l) {
30342                 return l.map(point);
30343               }
30344
30345               function poly(p) {
30346                 return p.map(multi);
30347               }
30348
30349               function multiPoly(m) {
30350                 return m.map(poly);
30351               }
30352
30353               function geometry(obj) {
30354                 if (!obj) {
30355                   return {};
30356                 }
30357
30358                 switch (obj.type) {
30359                   case "Point":
30360                     obj.coordinates = point(obj.coordinates);
30361                     return obj;
30362
30363                   case "LineString":
30364                   case "MultiPoint":
30365                     obj.coordinates = multi(obj.coordinates);
30366                     return obj;
30367
30368                   case "Polygon":
30369                   case "MultiLineString":
30370                     obj.coordinates = poly(obj.coordinates);
30371                     return obj;
30372
30373                   case "MultiPolygon":
30374                     obj.coordinates = multiPoly(obj.coordinates);
30375                     return obj;
30376
30377                   case "GeometryCollection":
30378                     obj.geometries = obj.geometries.map(geometry);
30379                     return obj;
30380
30381                   default:
30382                     return {};
30383                 }
30384               }
30385
30386               function feature(obj) {
30387                 obj.geometry = geometry(obj.geometry);
30388                 return obj;
30389               }
30390
30391               function featureCollection(f) {
30392                 f.features = f.features.map(feature);
30393                 return f;
30394               }
30395
30396               function geometryCollection(g) {
30397                 g.geometries = g.geometries.map(geometry);
30398                 return g;
30399               }
30400
30401               if (!t) {
30402                 return t;
30403               }
30404
30405               switch (t.type) {
30406                 case "Feature":
30407                   return feature(t);
30408
30409                 case "GeometryCollection":
30410                   return geometryCollection(t);
30411
30412                 case "FeatureCollection":
30413                   return featureCollection(t);
30414
30415                 case "Point":
30416                 case "LineString":
30417                 case "Polygon":
30418                 case "MultiPoint":
30419                 case "MultiPolygon":
30420                 case "MultiLineString":
30421                   return geometry(t);
30422
30423                 default:
30424                   return t;
30425               }
30426             }
30427
30428             module.exports = parse;
30429             module.exports.parse = parse;
30430           })();
30431         });
30432
30433         var FORCED$3 = fails(function () {
30434           return new Date(NaN).toJSON() !== null
30435             || Date.prototype.toJSON.call({ toISOString: function () { return 1; } }) !== 1;
30436         });
30437
30438         // `Date.prototype.toJSON` method
30439         // https://tc39.es/ecma262/#sec-date.prototype.tojson
30440         _export({ target: 'Date', proto: true, forced: FORCED$3 }, {
30441           // eslint-disable-next-line no-unused-vars -- required for `.length`
30442           toJSON: function toJSON(key) {
30443             var O = toObject(this);
30444             var pv = toPrimitive(O);
30445             return typeof pv == 'number' && !isFinite(pv) ? null : O.toISOString();
30446           }
30447         });
30448
30449         // `URL.prototype.toJSON` method
30450         // https://url.spec.whatwg.org/#dom-url-tojson
30451         _export({ target: 'URL', proto: true, enumerable: true }, {
30452           toJSON: function toJSON() {
30453             return URL.prototype.toString.call(this);
30454           }
30455         });
30456
30457         function isObject$3(obj) {
30458           return _typeof(obj) === 'object' && obj !== null;
30459         }
30460
30461         function forEach(obj, cb) {
30462           if (Array.isArray(obj)) {
30463             obj.forEach(cb);
30464           } else if (isObject$3(obj)) {
30465             Object.keys(obj).forEach(function (key) {
30466               var val = obj[key];
30467               cb(val, key);
30468             });
30469           }
30470         }
30471
30472         function getTreeDepth(obj) {
30473           var depth = 0;
30474
30475           if (Array.isArray(obj) || isObject$3(obj)) {
30476             forEach(obj, function (val) {
30477               if (Array.isArray(val) || isObject$3(val)) {
30478                 var tmpDepth = getTreeDepth(val);
30479
30480                 if (tmpDepth > depth) {
30481                   depth = tmpDepth;
30482                 }
30483               }
30484             });
30485             return depth + 1;
30486           }
30487
30488           return depth;
30489         }
30490
30491         function stringify(obj, options) {
30492           options = options || {};
30493           var indent = JSON.stringify([1], null, get(options, 'indent', 2)).slice(2, -3);
30494           var addMargin = get(options, 'margins', false);
30495           var addArrayMargin = get(options, 'arrayMargins', false);
30496           var addObjectMargin = get(options, 'objectMargins', false);
30497           var maxLength = indent === '' ? Infinity : get(options, 'maxLength', 80);
30498           var maxNesting = get(options, 'maxNesting', Infinity);
30499           return function _stringify(obj, currentIndent, reserved) {
30500             if (obj && typeof obj.toJSON === 'function') {
30501               obj = obj.toJSON();
30502             }
30503
30504             var string = JSON.stringify(obj);
30505
30506             if (string === undefined) {
30507               return string;
30508             }
30509
30510             var length = maxLength - currentIndent.length - reserved;
30511             var treeDepth = getTreeDepth(obj);
30512
30513             if (treeDepth <= maxNesting && string.length <= length) {
30514               var prettified = prettify(string, {
30515                 addMargin: addMargin,
30516                 addArrayMargin: addArrayMargin,
30517                 addObjectMargin: addObjectMargin
30518               });
30519
30520               if (prettified.length <= length) {
30521                 return prettified;
30522               }
30523             }
30524
30525             if (isObject$3(obj)) {
30526               var nextIndent = currentIndent + indent;
30527               var items = [];
30528               var delimiters;
30529
30530               var comma = function comma(array, index) {
30531                 return index === array.length - 1 ? 0 : 1;
30532               };
30533
30534               if (Array.isArray(obj)) {
30535                 for (var index = 0; index < obj.length; index++) {
30536                   items.push(_stringify(obj[index], nextIndent, comma(obj, index)) || 'null');
30537                 }
30538
30539                 delimiters = '[]';
30540               } else {
30541                 Object.keys(obj).forEach(function (key, index, array) {
30542                   var keyPart = JSON.stringify(key) + ': ';
30543
30544                   var value = _stringify(obj[key], nextIndent, keyPart.length + comma(array, index));
30545
30546                   if (value !== undefined) {
30547                     items.push(keyPart + value);
30548                   }
30549                 });
30550                 delimiters = '{}';
30551               }
30552
30553               if (items.length > 0) {
30554                 return [delimiters[0], indent + items.join(',\n' + nextIndent), delimiters[1]].join('\n' + currentIndent);
30555               }
30556             }
30557
30558             return string;
30559           }(obj, '', 0);
30560         } // Note: This regex matches even invalid JSON strings, but since we’re
30561         // working on the output of `JSON.stringify` we know that only valid strings
30562         // are present (unless the user supplied a weird `options.indent` but in
30563         // that case we don’t care since the output would be invalid anyway).
30564
30565
30566         var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g;
30567
30568         function prettify(string, options) {
30569           options = options || {};
30570           var tokens = {
30571             '{': '{',
30572             '}': '}',
30573             '[': '[',
30574             ']': ']',
30575             ',': ', ',
30576             ':': ': '
30577           };
30578
30579           if (options.addMargin || options.addObjectMargin) {
30580             tokens['{'] = '{ ';
30581             tokens['}'] = ' }';
30582           }
30583
30584           if (options.addMargin || options.addArrayMargin) {
30585             tokens['['] = '[ ';
30586             tokens[']'] = ' ]';
30587           }
30588
30589           return string.replace(stringOrChar, function (match, string) {
30590             return string ? match : tokens[match];
30591           });
30592         }
30593
30594         function get(options, name, defaultValue) {
30595           return name in options ? options[name] : defaultValue;
30596         }
30597
30598         var jsonStringifyPrettyCompact = stringify;
30599
30600         var _default = /*#__PURE__*/function () {
30601           // constructor
30602           //
30603           // `fc`  Optional FeatureCollection of known features
30604           //
30605           // Optionally pass a GeoJSON FeatureCollection of known features which we can refer to later.
30606           // Each feature must have a filename-like `id`, for example: `something.geojson`
30607           //
30608           // {
30609           //   "type": "FeatureCollection"
30610           //   "features": [
30611           //     {
30612           //       "type": "Feature",
30613           //       "id": "philly_metro.geojson",
30614           //       "properties": { … },
30615           //       "geometry": { … }
30616           //     }
30617           //   ]
30618           // }
30619           function _default(fc) {
30620             var _this = this;
30621
30622             _classCallCheck$1(this, _default);
30623
30624             // The _cache retains resolved features, so if you ask for the same thing multiple times
30625             // we don't repeat the expensive resolving/clipping operations.
30626             //
30627             // Each feature has a stable identifier that is used as the cache key.
30628             // The identifiers look like:
30629             // - for point locations, the stringified point:          e.g. '[8.67039,49.41882]'
30630             // - for geojson locations, the geojson id:               e.g. 'de-hamburg.geojson'
30631             // - for countrycoder locations, feature.id property:     e.g. 'Q2'  (countrycoder uses Wikidata identifiers)
30632             // - for aggregated locationSets, +[include]-[exclude]:   e.g '+[Q2]-[Q18,Q27611]'
30633             this._cache = {}; // When strict mode = true, throw on invalid locations or locationSets.
30634             // When strict mode = false, return `null` for invalid locations or locationSets.
30635
30636             this._strict = true; // process input FeatureCollection
30637
30638             if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
30639               fc.features.forEach(function (feature) {
30640                 feature.properties = feature.properties || {};
30641                 var props = feature.properties; // Get `id` from either `id` or `properties`
30642
30643                 var id = feature.id || props.id;
30644                 if (!id || !/^\S+\.geojson$/i.test(id)) return; // Ensure `id` exists and is lowercase
30645
30646                 id = id.toLowerCase();
30647                 feature.id = id;
30648                 props.id = id; // Ensure `area` property exists
30649
30650                 if (!props.area) {
30651                   var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
30652
30653                   props.area = Number(area.toFixed(2));
30654                 }
30655
30656                 _this._cache[id] = feature;
30657               });
30658             } // Replace CountryCoder world geometry to be a polygon covering the world.
30659
30660
30661             var world = _cloneDeep(feature$1('Q2'));
30662
30663             world.geometry = {
30664               type: 'Polygon',
30665               coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
30666             };
30667             world.id = 'Q2';
30668             world.properties.id = 'Q2';
30669             world.properties.area = geojsonArea.geometry(world.geometry) / 1e6; // m² to km²
30670
30671             this._cache.Q2 = world;
30672           } // validateLocation
30673           // `location`  The location to validate
30674           //
30675           // Pass a `location` value to validate
30676           //
30677           // Returns a result like:
30678           //   {
30679           //     type:     'point', 'geojson', or 'countrycoder'
30680           //     location:  the queried location
30681           //     id:        the stable identifier for the feature
30682           //   }
30683           // or `null` if the location is invalid
30684           //
30685
30686
30687           _createClass$1(_default, [{
30688             key: "validateLocation",
30689             value: function validateLocation(location) {
30690               if (Array.isArray(location) && (location.length === 2 || location.length === 3)) {
30691                 // [lon, lat] or [lon, lat, radius] point?
30692                 var lon = location[0];
30693                 var lat = location[1];
30694                 var radius = location[2];
30695
30696                 if (Number.isFinite(lon) && lon >= -180 && lon <= 180 && Number.isFinite(lat) && lat >= -90 && lat <= 90 && (location.length === 2 || Number.isFinite(radius) && radius > 0)) {
30697                   var id = '[' + location.toString() + ']';
30698                   return {
30699                     type: 'point',
30700                     location: location,
30701                     id: id
30702                   };
30703                 }
30704               } else if (typeof location === 'string' && /^\S+\.geojson$/i.test(location)) {
30705                 // a .geojson filename?
30706                 var _id = location.toLowerCase();
30707
30708                 if (this._cache[_id]) {
30709                   return {
30710                     type: 'geojson',
30711                     location: location,
30712                     id: _id
30713                   };
30714                 }
30715               } else if (typeof location === 'string' || typeof location === 'number') {
30716                 // a country-coder value?
30717                 var feature = feature$1(location);
30718
30719                 if (feature) {
30720                   // Use wikidata QID as the identifier, since that seems to be the one
30721                   // property that everything in CountryCoder is guaranteed to have.
30722                   var _id2 = feature.properties.wikidata;
30723                   return {
30724                     type: 'countrycoder',
30725                     location: location,
30726                     id: _id2
30727                   };
30728                 }
30729               }
30730
30731               if (this._strict) {
30732                 throw new Error("validateLocation:  Invalid location: \"".concat(location, "\"."));
30733               } else {
30734                 return null;
30735               }
30736             } // resolveLocation
30737             // `location`  The location to resolve
30738             //
30739             // Pass a `location` value to resolve
30740             //
30741             // Returns a result like:
30742             //   {
30743             //     type:      'point', 'geojson', or 'countrycoder'
30744             //     location:  the queried location
30745             //     id:        a stable identifier for the feature
30746             //     feature:   the resolved GeoJSON feature
30747             //   }
30748             //  or `null` if the location is invalid
30749             //
30750
30751           }, {
30752             key: "resolveLocation",
30753             value: function resolveLocation(location) {
30754               var valid = this.validateLocation(location);
30755               if (!valid) return null;
30756               var id = valid.id; // Return a result from cache if we can
30757
30758               if (this._cache[id]) {
30759                 return Object.assign(valid, {
30760                   feature: this._cache[id]
30761                 });
30762               } // A [lon,lat] coordinate pair?
30763
30764
30765               if (valid.type === 'point') {
30766                 var lon = location[0];
30767                 var lat = location[1];
30768                 var radius = location[2] || 25; // km
30769
30770                 var EDGES = 10;
30771                 var PRECISION = 3;
30772                 var area = Math.PI * radius * radius;
30773                 var feature = this._cache[id] = geojsonPrecision({
30774                   type: 'Feature',
30775                   id: id,
30776                   properties: {
30777                     id: id,
30778                     area: Number(area.toFixed(2))
30779                   },
30780                   geometry: circleToPolygon([lon, lat], radius * 1000, EDGES) // km to m
30781
30782                 }, PRECISION);
30783                 return Object.assign(valid, {
30784                   feature: feature
30785                 }); // A .geojson filename?
30786               } else if (valid.type === 'geojson') ; else if (valid.type === 'countrycoder') {
30787                 var _feature = _cloneDeep(feature$1(id));
30788
30789                 var props = _feature.properties; // -> This block of code is weird and requires some explanation. <-
30790                 // CountryCoder includes higher level features which are made up of members.
30791                 // These features don't have their own geometry, but CountryCoder provides an
30792                 //   `aggregateFeature` method to combine these members into a MultiPolygon.
30793                 // In the past, Turf/JSTS/martinez could not handle the aggregated features,
30794                 //   so we'd iteratively union them all together.  (this was slow)
30795                 // But now mfogel/polygon-clipping handles these MultiPolygons like a boss.
30796                 // This approach also has the benefit of removing all the internal boaders and
30797                 //   simplifying the regional polygons a lot.
30798
30799                 if (Array.isArray(props.members)) {
30800                   var aggregate = aggregateFeature(id);
30801                   aggregate.geometry.coordinates = _clip([aggregate], 'UNION').geometry.coordinates;
30802                   _feature.geometry = aggregate.geometry;
30803                 } // Ensure `area` property exists
30804
30805
30806                 if (!props.area) {
30807                   var _area = geojsonArea.geometry(_feature.geometry) / 1e6; // m² to km²
30808
30809
30810                   props.area = Number(_area.toFixed(2));
30811                 } // Ensure `id` property exists
30812
30813
30814                 _feature.id = id;
30815                 props.id = id;
30816                 this._cache[id] = _feature;
30817                 return Object.assign(valid, {
30818                   feature: _feature
30819                 });
30820               }
30821
30822               if (this._strict) {
30823                 throw new Error("resolveLocation:  Couldn't resolve location \"".concat(location, "\"."));
30824               } else {
30825                 return null;
30826               }
30827             } // validateLocationSet
30828             // `locationSet`  the locationSet to validate
30829             //
30830             // Pass a locationSet Object to validate like:
30831             //   {
30832             //     include: [ Array of locations ],
30833             //     exclude: [ Array of locations ]
30834             //   }
30835             //
30836             // Returns a result like:
30837             //   {
30838             //     type:         'locationset'
30839             //     locationSet:  the queried locationSet
30840             //     id:           the stable identifier for the feature
30841             //   }
30842             // or `null` if the locationSet is invalid
30843             //
30844
30845           }, {
30846             key: "validateLocationSet",
30847             value: function validateLocationSet(locationSet) {
30848               locationSet = locationSet || {};
30849               var validator = this.validateLocation.bind(this);
30850               var include = (locationSet.include || []).map(validator).filter(Boolean);
30851               var exclude = (locationSet.exclude || []).map(validator).filter(Boolean);
30852
30853               if (!include.length) {
30854                 if (this._strict) {
30855                   throw new Error("validateLocationSet:  LocationSet includes nothing.");
30856                 } else {
30857                   // non-strict mode, replace an empty locationSet with one that includes "the world"
30858                   locationSet.include = ['Q2'];
30859                   include = [{
30860                     type: 'countrycoder',
30861                     location: 'Q2',
30862                     id: 'Q2'
30863                   }];
30864                 }
30865               } // Generate stable identifier
30866
30867
30868               include.sort(_sortLocations);
30869               var id = '+[' + include.map(function (d) {
30870                 return d.id;
30871               }).join(',') + ']';
30872
30873               if (exclude.length) {
30874                 exclude.sort(_sortLocations);
30875                 id += '-[' + exclude.map(function (d) {
30876                   return d.id;
30877                 }).join(',') + ']';
30878               }
30879
30880               return {
30881                 type: 'locationset',
30882                 locationSet: locationSet,
30883                 id: id
30884               };
30885             } // resolveLocationSet
30886             // `locationSet`  the locationSet to resolve
30887             //
30888             // Pass a locationSet Object to validate like:
30889             //   {
30890             //     include: [ Array of locations ],
30891             //     exclude: [ Array of locations ]
30892             //   }
30893             //
30894             // Returns a result like:
30895             //   {
30896             //     type:         'locationset'
30897             //     locationSet:  the queried locationSet
30898             //     id:           the stable identifier for the feature
30899             //     feature:      the resolved GeoJSON feature
30900             //   }
30901             // or `null` if the locationSet is invalid
30902             //
30903
30904           }, {
30905             key: "resolveLocationSet",
30906             value: function resolveLocationSet(locationSet) {
30907               locationSet = locationSet || {};
30908               var valid = this.validateLocationSet(locationSet);
30909               if (!valid) return null;
30910               var id = valid.id; // Return a result from cache if we can
30911
30912               if (this._cache[id]) {
30913                 return Object.assign(valid, {
30914                   feature: this._cache[id]
30915                 });
30916               }
30917
30918               var resolver = this.resolveLocation.bind(this);
30919               var includes = (locationSet.include || []).map(resolver).filter(Boolean);
30920               var excludes = (locationSet.exclude || []).map(resolver).filter(Boolean); // Return quickly if it's a single included location..
30921
30922               if (includes.length === 1 && excludes.length === 0) {
30923                 return Object.assign(valid, {
30924                   feature: includes[0].feature
30925                 });
30926               } // Calculate unions
30927
30928
30929               var includeGeoJSON = _clip(includes.map(function (d) {
30930                 return d.feature;
30931               }), 'UNION');
30932
30933               var excludeGeoJSON = _clip(excludes.map(function (d) {
30934                 return d.feature;
30935               }), 'UNION'); // Calculate difference, update `area` and return result
30936
30937
30938               var resultGeoJSON = excludeGeoJSON ? _clip([includeGeoJSON, excludeGeoJSON], 'DIFFERENCE') : includeGeoJSON;
30939               var area = geojsonArea.geometry(resultGeoJSON.geometry) / 1e6; // m² to km²
30940
30941               resultGeoJSON.id = id;
30942               resultGeoJSON.properties = {
30943                 id: id,
30944                 area: Number(area.toFixed(2))
30945               };
30946               this._cache[id] = resultGeoJSON;
30947               return Object.assign(valid, {
30948                 feature: resultGeoJSON
30949               });
30950             } // strict
30951             //
30952
30953           }, {
30954             key: "strict",
30955             value: function strict(val) {
30956               if (val === undefined) {
30957                 // get
30958                 return this._strict;
30959               } else {
30960                 // set
30961                 this._strict = val;
30962                 return this;
30963               }
30964             } // cache
30965             // convenience method to access the internal cache
30966
30967           }, {
30968             key: "cache",
30969             value: function cache() {
30970               return this._cache;
30971             } // stringify
30972             // convenience method to prettyStringify the given object
30973
30974           }, {
30975             key: "stringify",
30976             value: function stringify(obj, options) {
30977               return jsonStringifyPrettyCompact(obj, options);
30978             }
30979           }]);
30980
30981           return _default;
30982         }(); // Wrap the mfogel/polygon-clipping library and return a GeoJSON feature.
30983
30984         function _clip(features, which) {
30985           if (!Array.isArray(features) || !features.length) return null;
30986           var fn = {
30987             UNION: index.union,
30988             DIFFERENCE: index.difference
30989           }[which];
30990           var args = features.map(function (feature) {
30991             return feature.geometry.coordinates;
30992           });
30993           var coords = fn.apply(null, args);
30994           return {
30995             type: 'Feature',
30996             properties: {},
30997             geometry: {
30998               type: whichType(coords),
30999               coordinates: coords
31000             }
31001           }; // is this a Polygon or a MultiPolygon?
31002
31003           function whichType(coords) {
31004             var a = Array.isArray(coords);
31005             var b = a && Array.isArray(coords[0]);
31006             var c = b && Array.isArray(coords[0][0]);
31007             var d = c && Array.isArray(coords[0][0][0]);
31008             return d ? 'MultiPolygon' : 'Polygon';
31009           }
31010         }
31011
31012         function _cloneDeep(obj) {
31013           return JSON.parse(JSON.stringify(obj));
31014         } // Sorting the location lists is ok because they end up unioned together.
31015         // This sorting makes it possible to generate a deterministic id.
31016
31017
31018         function _sortLocations(a, b) {
31019           var rank = {
31020             countrycoder: 1,
31021             geojson: 2,
31022             point: 3
31023           };
31024           var aRank = rank[a.type];
31025           var bRank = rank[b.type];
31026           return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);
31027         }
31028
31029         // `Number.MAX_SAFE_INTEGER` constant
31030         // https://tc39.es/ecma262/#sec-number.max_safe_integer
31031         _export({ target: 'Number', stat: true }, {
31032           MAX_SAFE_INTEGER: 0x1FFFFFFFFFFFFF
31033         });
31034
31035         var aesJs = createCommonjsModule(function (module, exports) {
31036           (function (root) {
31037
31038             function checkInt(value) {
31039               return parseInt(value) === value;
31040             }
31041
31042             function checkInts(arrayish) {
31043               if (!checkInt(arrayish.length)) {
31044                 return false;
31045               }
31046
31047               for (var i = 0; i < arrayish.length; i++) {
31048                 if (!checkInt(arrayish[i]) || arrayish[i] < 0 || arrayish[i] > 255) {
31049                   return false;
31050                 }
31051               }
31052
31053               return true;
31054             }
31055
31056             function coerceArray(arg, copy) {
31057               // ArrayBuffer view
31058               if (arg.buffer && arg.name === 'Uint8Array') {
31059                 if (copy) {
31060                   if (arg.slice) {
31061                     arg = arg.slice();
31062                   } else {
31063                     arg = Array.prototype.slice.call(arg);
31064                   }
31065                 }
31066
31067                 return arg;
31068               } // It's an array; check it is a valid representation of a byte
31069
31070
31071               if (Array.isArray(arg)) {
31072                 if (!checkInts(arg)) {
31073                   throw new Error('Array contains invalid value: ' + arg);
31074                 }
31075
31076                 return new Uint8Array(arg);
31077               } // Something else, but behaves like an array (maybe a Buffer? Arguments?)
31078
31079
31080               if (checkInt(arg.length) && checkInts(arg)) {
31081                 return new Uint8Array(arg);
31082               }
31083
31084               throw new Error('unsupported array-like object');
31085             }
31086
31087             function createArray(length) {
31088               return new Uint8Array(length);
31089             }
31090
31091             function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
31092               if (sourceStart != null || sourceEnd != null) {
31093                 if (sourceArray.slice) {
31094                   sourceArray = sourceArray.slice(sourceStart, sourceEnd);
31095                 } else {
31096                   sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
31097                 }
31098               }
31099
31100               targetArray.set(sourceArray, targetStart);
31101             }
31102
31103             var convertUtf8 = function () {
31104               function toBytes(text) {
31105                 var result = [],
31106                     i = 0;
31107                 text = encodeURI(text);
31108
31109                 while (i < text.length) {
31110                   var c = text.charCodeAt(i++); // if it is a % sign, encode the following 2 bytes as a hex value
31111
31112                   if (c === 37) {
31113                     result.push(parseInt(text.substr(i, 2), 16));
31114                     i += 2; // otherwise, just the actual byte
31115                   } else {
31116                     result.push(c);
31117                   }
31118                 }
31119
31120                 return coerceArray(result);
31121               }
31122
31123               function fromBytes(bytes) {
31124                 var result = [],
31125                     i = 0;
31126
31127                 while (i < bytes.length) {
31128                   var c = bytes[i];
31129
31130                   if (c < 128) {
31131                     result.push(String.fromCharCode(c));
31132                     i++;
31133                   } else if (c > 191 && c < 224) {
31134                     result.push(String.fromCharCode((c & 0x1f) << 6 | bytes[i + 1] & 0x3f));
31135                     i += 2;
31136                   } else {
31137                     result.push(String.fromCharCode((c & 0x0f) << 12 | (bytes[i + 1] & 0x3f) << 6 | bytes[i + 2] & 0x3f));
31138                     i += 3;
31139                   }
31140                 }
31141
31142                 return result.join('');
31143               }
31144
31145               return {
31146                 toBytes: toBytes,
31147                 fromBytes: fromBytes
31148               };
31149             }();
31150
31151             var convertHex = function () {
31152               function toBytes(text) {
31153                 var result = [];
31154
31155                 for (var i = 0; i < text.length; i += 2) {
31156                   result.push(parseInt(text.substr(i, 2), 16));
31157                 }
31158
31159                 return result;
31160               } // http://ixti.net/development/javascript/2011/11/11/base64-encodedecode-of-utf8-in-browser-with-js.html
31161
31162
31163               var Hex = '0123456789abcdef';
31164
31165               function fromBytes(bytes) {
31166                 var result = [];
31167
31168                 for (var i = 0; i < bytes.length; i++) {
31169                   var v = bytes[i];
31170                   result.push(Hex[(v & 0xf0) >> 4] + Hex[v & 0x0f]);
31171                 }
31172
31173                 return result.join('');
31174               }
31175
31176               return {
31177                 toBytes: toBytes,
31178                 fromBytes: fromBytes
31179               };
31180             }(); // Number of rounds by keysize
31181
31182
31183             var numberOfRounds = {
31184               16: 10,
31185               24: 12,
31186               32: 14
31187             }; // Round constant words
31188
31189             var rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91]; // S-box and Inverse S-box (S is for Substitution)
31190
31191             var S = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16];
31192             var Si = [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]; // Transformations for encryption
31193
31194             var T1 = [0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a];
31195             var T2 = [0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616];
31196             var T3 = [0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16];
31197             var T4 = [0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c]; // Transformations for decryption
31198
31199             var T5 = [0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742];
31200             var T6 = [0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857];
31201             var T7 = [0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8];
31202             var T8 = [0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0]; // Transformations for decryption key expansion
31203
31204             var U1 = [0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3];
31205             var U2 = [0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697];
31206             var U3 = [0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46];
31207             var U4 = [0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d];
31208
31209             function convertToInt32(bytes) {
31210               var result = [];
31211
31212               for (var i = 0; i < bytes.length; i += 4) {
31213                 result.push(bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]);
31214               }
31215
31216               return result;
31217             }
31218
31219             var AES = function AES(key) {
31220               if (!(this instanceof AES)) {
31221                 throw Error('AES must be instanitated with `new`');
31222               }
31223
31224               Object.defineProperty(this, 'key', {
31225                 value: coerceArray(key, true)
31226               });
31227
31228               this._prepare();
31229             };
31230
31231             AES.prototype._prepare = function () {
31232               var rounds = numberOfRounds[this.key.length];
31233
31234               if (rounds == null) {
31235                 throw new Error('invalid key size (must be 16, 24 or 32 bytes)');
31236               } // encryption round keys
31237
31238
31239               this._Ke = []; // decryption round keys
31240
31241               this._Kd = [];
31242
31243               for (var i = 0; i <= rounds; i++) {
31244                 this._Ke.push([0, 0, 0, 0]);
31245
31246                 this._Kd.push([0, 0, 0, 0]);
31247               }
31248
31249               var roundKeyCount = (rounds + 1) * 4;
31250               var KC = this.key.length / 4; // convert the key into ints
31251
31252               var tk = convertToInt32(this.key); // copy values into round key arrays
31253
31254               var index;
31255
31256               for (var i = 0; i < KC; i++) {
31257                 index = i >> 2;
31258                 this._Ke[index][i % 4] = tk[i];
31259                 this._Kd[rounds - index][i % 4] = tk[i];
31260               } // key expansion (fips-197 section 5.2)
31261
31262
31263               var rconpointer = 0;
31264               var t = KC,
31265                   tt;
31266
31267               while (t < roundKeyCount) {
31268                 tt = tk[KC - 1];
31269                 tk[0] ^= S[tt >> 16 & 0xFF] << 24 ^ S[tt >> 8 & 0xFF] << 16 ^ S[tt & 0xFF] << 8 ^ S[tt >> 24 & 0xFF] ^ rcon[rconpointer] << 24;
31270                 rconpointer += 1; // key expansion (for non-256 bit)
31271
31272                 if (KC != 8) {
31273                   for (var i = 1; i < KC; i++) {
31274                     tk[i] ^= tk[i - 1];
31275                   } // key expansion for 256-bit keys is "slightly different" (fips-197)
31276
31277                 } else {
31278                   for (var i = 1; i < KC / 2; i++) {
31279                     tk[i] ^= tk[i - 1];
31280                   }
31281
31282                   tt = tk[KC / 2 - 1];
31283                   tk[KC / 2] ^= S[tt & 0xFF] ^ S[tt >> 8 & 0xFF] << 8 ^ S[tt >> 16 & 0xFF] << 16 ^ S[tt >> 24 & 0xFF] << 24;
31284
31285                   for (var i = KC / 2 + 1; i < KC; i++) {
31286                     tk[i] ^= tk[i - 1];
31287                   }
31288                 } // copy values into round key arrays
31289
31290
31291                 var i = 0,
31292                     r,
31293                     c;
31294
31295                 while (i < KC && t < roundKeyCount) {
31296                   r = t >> 2;
31297                   c = t % 4;
31298                   this._Ke[r][c] = tk[i];
31299                   this._Kd[rounds - r][c] = tk[i++];
31300                   t++;
31301                 }
31302               } // inverse-cipher-ify the decryption round key (fips-197 section 5.3)
31303
31304
31305               for (var r = 1; r < rounds; r++) {
31306                 for (var c = 0; c < 4; c++) {
31307                   tt = this._Kd[r][c];
31308                   this._Kd[r][c] = U1[tt >> 24 & 0xFF] ^ U2[tt >> 16 & 0xFF] ^ U3[tt >> 8 & 0xFF] ^ U4[tt & 0xFF];
31309                 }
31310               }
31311             };
31312
31313             AES.prototype.encrypt = function (plaintext) {
31314               if (plaintext.length != 16) {
31315                 throw new Error('invalid plaintext size (must be 16 bytes)');
31316               }
31317
31318               var rounds = this._Ke.length - 1;
31319               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
31320
31321               var t = convertToInt32(plaintext);
31322
31323               for (var i = 0; i < 4; i++) {
31324                 t[i] ^= this._Ke[0][i];
31325               } // apply round transforms
31326
31327
31328               for (var r = 1; r < rounds; r++) {
31329                 for (var i = 0; i < 4; i++) {
31330                   a[i] = T1[t[i] >> 24 & 0xff] ^ T2[t[(i + 1) % 4] >> 16 & 0xff] ^ T3[t[(i + 2) % 4] >> 8 & 0xff] ^ T4[t[(i + 3) % 4] & 0xff] ^ this._Ke[r][i];
31331                 }
31332
31333                 t = a.slice();
31334               } // the last round is special
31335
31336
31337               var result = createArray(16),
31338                   tt;
31339
31340               for (var i = 0; i < 4; i++) {
31341                 tt = this._Ke[rounds][i];
31342                 result[4 * i] = (S[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
31343                 result[4 * i + 1] = (S[t[(i + 1) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
31344                 result[4 * i + 2] = (S[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
31345                 result[4 * i + 3] = (S[t[(i + 3) % 4] & 0xff] ^ tt) & 0xff;
31346               }
31347
31348               return result;
31349             };
31350
31351             AES.prototype.decrypt = function (ciphertext) {
31352               if (ciphertext.length != 16) {
31353                 throw new Error('invalid ciphertext size (must be 16 bytes)');
31354               }
31355
31356               var rounds = this._Kd.length - 1;
31357               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
31358
31359               var t = convertToInt32(ciphertext);
31360
31361               for (var i = 0; i < 4; i++) {
31362                 t[i] ^= this._Kd[0][i];
31363               } // apply round transforms
31364
31365
31366               for (var r = 1; r < rounds; r++) {
31367                 for (var i = 0; i < 4; i++) {
31368                   a[i] = T5[t[i] >> 24 & 0xff] ^ T6[t[(i + 3) % 4] >> 16 & 0xff] ^ T7[t[(i + 2) % 4] >> 8 & 0xff] ^ T8[t[(i + 1) % 4] & 0xff] ^ this._Kd[r][i];
31369                 }
31370
31371                 t = a.slice();
31372               } // the last round is special
31373
31374
31375               var result = createArray(16),
31376                   tt;
31377
31378               for (var i = 0; i < 4; i++) {
31379                 tt = this._Kd[rounds][i];
31380                 result[4 * i] = (Si[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
31381                 result[4 * i + 1] = (Si[t[(i + 3) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
31382                 result[4 * i + 2] = (Si[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
31383                 result[4 * i + 3] = (Si[t[(i + 1) % 4] & 0xff] ^ tt) & 0xff;
31384               }
31385
31386               return result;
31387             };
31388             /**
31389              *  Mode Of Operation - Electonic Codebook (ECB)
31390              */
31391
31392
31393             var ModeOfOperationECB = function ModeOfOperationECB(key) {
31394               if (!(this instanceof ModeOfOperationECB)) {
31395                 throw Error('AES must be instanitated with `new`');
31396               }
31397
31398               this.description = "Electronic Code Block";
31399               this.name = "ecb";
31400               this._aes = new AES(key);
31401             };
31402
31403             ModeOfOperationECB.prototype.encrypt = function (plaintext) {
31404               plaintext = coerceArray(plaintext);
31405
31406               if (plaintext.length % 16 !== 0) {
31407                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
31408               }
31409
31410               var ciphertext = createArray(plaintext.length);
31411               var block = createArray(16);
31412
31413               for (var i = 0; i < plaintext.length; i += 16) {
31414                 copyArray(plaintext, block, 0, i, i + 16);
31415                 block = this._aes.encrypt(block);
31416                 copyArray(block, ciphertext, i);
31417               }
31418
31419               return ciphertext;
31420             };
31421
31422             ModeOfOperationECB.prototype.decrypt = function (ciphertext) {
31423               ciphertext = coerceArray(ciphertext);
31424
31425               if (ciphertext.length % 16 !== 0) {
31426                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
31427               }
31428
31429               var plaintext = createArray(ciphertext.length);
31430               var block = createArray(16);
31431
31432               for (var i = 0; i < ciphertext.length; i += 16) {
31433                 copyArray(ciphertext, block, 0, i, i + 16);
31434                 block = this._aes.decrypt(block);
31435                 copyArray(block, plaintext, i);
31436               }
31437
31438               return plaintext;
31439             };
31440             /**
31441              *  Mode Of Operation - Cipher Block Chaining (CBC)
31442              */
31443
31444
31445             var ModeOfOperationCBC = function ModeOfOperationCBC(key, iv) {
31446               if (!(this instanceof ModeOfOperationCBC)) {
31447                 throw Error('AES must be instanitated with `new`');
31448               }
31449
31450               this.description = "Cipher Block Chaining";
31451               this.name = "cbc";
31452
31453               if (!iv) {
31454                 iv = createArray(16);
31455               } else if (iv.length != 16) {
31456                 throw new Error('invalid initialation vector size (must be 16 bytes)');
31457               }
31458
31459               this._lastCipherblock = coerceArray(iv, true);
31460               this._aes = new AES(key);
31461             };
31462
31463             ModeOfOperationCBC.prototype.encrypt = function (plaintext) {
31464               plaintext = coerceArray(plaintext);
31465
31466               if (plaintext.length % 16 !== 0) {
31467                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
31468               }
31469
31470               var ciphertext = createArray(plaintext.length);
31471               var block = createArray(16);
31472
31473               for (var i = 0; i < plaintext.length; i += 16) {
31474                 copyArray(plaintext, block, 0, i, i + 16);
31475
31476                 for (var j = 0; j < 16; j++) {
31477                   block[j] ^= this._lastCipherblock[j];
31478                 }
31479
31480                 this._lastCipherblock = this._aes.encrypt(block);
31481                 copyArray(this._lastCipherblock, ciphertext, i);
31482               }
31483
31484               return ciphertext;
31485             };
31486
31487             ModeOfOperationCBC.prototype.decrypt = function (ciphertext) {
31488               ciphertext = coerceArray(ciphertext);
31489
31490               if (ciphertext.length % 16 !== 0) {
31491                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
31492               }
31493
31494               var plaintext = createArray(ciphertext.length);
31495               var block = createArray(16);
31496
31497               for (var i = 0; i < ciphertext.length; i += 16) {
31498                 copyArray(ciphertext, block, 0, i, i + 16);
31499                 block = this._aes.decrypt(block);
31500
31501                 for (var j = 0; j < 16; j++) {
31502                   plaintext[i + j] = block[j] ^ this._lastCipherblock[j];
31503                 }
31504
31505                 copyArray(ciphertext, this._lastCipherblock, 0, i, i + 16);
31506               }
31507
31508               return plaintext;
31509             };
31510             /**
31511              *  Mode Of Operation - Cipher Feedback (CFB)
31512              */
31513
31514
31515             var ModeOfOperationCFB = function ModeOfOperationCFB(key, iv, segmentSize) {
31516               if (!(this instanceof ModeOfOperationCFB)) {
31517                 throw Error('AES must be instanitated with `new`');
31518               }
31519
31520               this.description = "Cipher Feedback";
31521               this.name = "cfb";
31522
31523               if (!iv) {
31524                 iv = createArray(16);
31525               } else if (iv.length != 16) {
31526                 throw new Error('invalid initialation vector size (must be 16 size)');
31527               }
31528
31529               if (!segmentSize) {
31530                 segmentSize = 1;
31531               }
31532
31533               this.segmentSize = segmentSize;
31534               this._shiftRegister = coerceArray(iv, true);
31535               this._aes = new AES(key);
31536             };
31537
31538             ModeOfOperationCFB.prototype.encrypt = function (plaintext) {
31539               if (plaintext.length % this.segmentSize != 0) {
31540                 throw new Error('invalid plaintext size (must be segmentSize bytes)');
31541               }
31542
31543               var encrypted = coerceArray(plaintext, true);
31544               var xorSegment;
31545
31546               for (var i = 0; i < encrypted.length; i += this.segmentSize) {
31547                 xorSegment = this._aes.encrypt(this._shiftRegister);
31548
31549                 for (var j = 0; j < this.segmentSize; j++) {
31550                   encrypted[i + j] ^= xorSegment[j];
31551                 } // Shift the register
31552
31553
31554                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
31555                 copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
31556               }
31557
31558               return encrypted;
31559             };
31560
31561             ModeOfOperationCFB.prototype.decrypt = function (ciphertext) {
31562               if (ciphertext.length % this.segmentSize != 0) {
31563                 throw new Error('invalid ciphertext size (must be segmentSize bytes)');
31564               }
31565
31566               var plaintext = coerceArray(ciphertext, true);
31567               var xorSegment;
31568
31569               for (var i = 0; i < plaintext.length; i += this.segmentSize) {
31570                 xorSegment = this._aes.encrypt(this._shiftRegister);
31571
31572                 for (var j = 0; j < this.segmentSize; j++) {
31573                   plaintext[i + j] ^= xorSegment[j];
31574                 } // Shift the register
31575
31576
31577                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
31578                 copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
31579               }
31580
31581               return plaintext;
31582             };
31583             /**
31584              *  Mode Of Operation - Output Feedback (OFB)
31585              */
31586
31587
31588             var ModeOfOperationOFB = function ModeOfOperationOFB(key, iv) {
31589               if (!(this instanceof ModeOfOperationOFB)) {
31590                 throw Error('AES must be instanitated with `new`');
31591               }
31592
31593               this.description = "Output Feedback";
31594               this.name = "ofb";
31595
31596               if (!iv) {
31597                 iv = createArray(16);
31598               } else if (iv.length != 16) {
31599                 throw new Error('invalid initialation vector size (must be 16 bytes)');
31600               }
31601
31602               this._lastPrecipher = coerceArray(iv, true);
31603               this._lastPrecipherIndex = 16;
31604               this._aes = new AES(key);
31605             };
31606
31607             ModeOfOperationOFB.prototype.encrypt = function (plaintext) {
31608               var encrypted = coerceArray(plaintext, true);
31609
31610               for (var i = 0; i < encrypted.length; i++) {
31611                 if (this._lastPrecipherIndex === 16) {
31612                   this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
31613                   this._lastPrecipherIndex = 0;
31614                 }
31615
31616                 encrypted[i] ^= this._lastPrecipher[this._lastPrecipherIndex++];
31617               }
31618
31619               return encrypted;
31620             }; // Decryption is symetric
31621
31622
31623             ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
31624             /**
31625              *  Counter object for CTR common mode of operation
31626              */
31627
31628             var Counter = function Counter(initialValue) {
31629               if (!(this instanceof Counter)) {
31630                 throw Error('Counter must be instanitated with `new`');
31631               } // We allow 0, but anything false-ish uses the default 1
31632
31633
31634               if (initialValue !== 0 && !initialValue) {
31635                 initialValue = 1;
31636               }
31637
31638               if (typeof initialValue === 'number') {
31639                 this._counter = createArray(16);
31640                 this.setValue(initialValue);
31641               } else {
31642                 this.setBytes(initialValue);
31643               }
31644             };
31645
31646             Counter.prototype.setValue = function (value) {
31647               if (typeof value !== 'number' || parseInt(value) != value) {
31648                 throw new Error('invalid counter value (must be an integer)');
31649               } // We cannot safely handle numbers beyond the safe range for integers
31650
31651
31652               if (value > Number.MAX_SAFE_INTEGER) {
31653                 throw new Error('integer value out of safe range');
31654               }
31655
31656               for (var index = 15; index >= 0; --index) {
31657                 this._counter[index] = value % 256;
31658                 value = parseInt(value / 256);
31659               }
31660             };
31661
31662             Counter.prototype.setBytes = function (bytes) {
31663               bytes = coerceArray(bytes, true);
31664
31665               if (bytes.length != 16) {
31666                 throw new Error('invalid counter bytes size (must be 16 bytes)');
31667               }
31668
31669               this._counter = bytes;
31670             };
31671
31672             Counter.prototype.increment = function () {
31673               for (var i = 15; i >= 0; i--) {
31674                 if (this._counter[i] === 255) {
31675                   this._counter[i] = 0;
31676                 } else {
31677                   this._counter[i]++;
31678                   break;
31679                 }
31680               }
31681             };
31682             /**
31683              *  Mode Of Operation - Counter (CTR)
31684              */
31685
31686
31687             var ModeOfOperationCTR = function ModeOfOperationCTR(key, counter) {
31688               if (!(this instanceof ModeOfOperationCTR)) {
31689                 throw Error('AES must be instanitated with `new`');
31690               }
31691
31692               this.description = "Counter";
31693               this.name = "ctr";
31694
31695               if (!(counter instanceof Counter)) {
31696                 counter = new Counter(counter);
31697               }
31698
31699               this._counter = counter;
31700               this._remainingCounter = null;
31701               this._remainingCounterIndex = 16;
31702               this._aes = new AES(key);
31703             };
31704
31705             ModeOfOperationCTR.prototype.encrypt = function (plaintext) {
31706               var encrypted = coerceArray(plaintext, true);
31707
31708               for (var i = 0; i < encrypted.length; i++) {
31709                 if (this._remainingCounterIndex === 16) {
31710                   this._remainingCounter = this._aes.encrypt(this._counter._counter);
31711                   this._remainingCounterIndex = 0;
31712
31713                   this._counter.increment();
31714                 }
31715
31716                 encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
31717               }
31718
31719               return encrypted;
31720             }; // Decryption is symetric
31721
31722
31723             ModeOfOperationCTR.prototype.decrypt = ModeOfOperationCTR.prototype.encrypt; ///////////////////////
31724             // Padding
31725             // See:https://tools.ietf.org/html/rfc2315
31726
31727             function pkcs7pad(data) {
31728               data = coerceArray(data, true);
31729               var padder = 16 - data.length % 16;
31730               var result = createArray(data.length + padder);
31731               copyArray(data, result);
31732
31733               for (var i = data.length; i < result.length; i++) {
31734                 result[i] = padder;
31735               }
31736
31737               return result;
31738             }
31739
31740             function pkcs7strip(data) {
31741               data = coerceArray(data, true);
31742
31743               if (data.length < 16) {
31744                 throw new Error('PKCS#7 invalid length');
31745               }
31746
31747               var padder = data[data.length - 1];
31748
31749               if (padder > 16) {
31750                 throw new Error('PKCS#7 padding byte out of range');
31751               }
31752
31753               var length = data.length - padder;
31754
31755               for (var i = 0; i < padder; i++) {
31756                 if (data[length + i] !== padder) {
31757                   throw new Error('PKCS#7 invalid padding byte');
31758                 }
31759               }
31760
31761               var result = createArray(length);
31762               copyArray(data, result, 0, 0, length);
31763               return result;
31764             } ///////////////////////
31765             // Exporting
31766             // The block cipher
31767
31768
31769             var aesjs = {
31770               AES: AES,
31771               Counter: Counter,
31772               ModeOfOperation: {
31773                 ecb: ModeOfOperationECB,
31774                 cbc: ModeOfOperationCBC,
31775                 cfb: ModeOfOperationCFB,
31776                 ofb: ModeOfOperationOFB,
31777                 ctr: ModeOfOperationCTR
31778               },
31779               utils: {
31780                 hex: convertHex,
31781                 utf8: convertUtf8
31782               },
31783               padding: {
31784                 pkcs7: {
31785                   pad: pkcs7pad,
31786                   strip: pkcs7strip
31787                 }
31788               },
31789               _arrayTest: {
31790                 coerceArray: coerceArray,
31791                 createArray: createArray,
31792                 copyArray: copyArray
31793               }
31794             }; // node.js
31795
31796             {
31797               module.exports = aesjs; // RequireJS/AMD
31798               // http://www.requirejs.org/docs/api.html
31799               // https://github.com/amdjs/amdjs-api/wiki/AMD
31800             }
31801           })();
31802         });
31803
31804         // We can use keys that are 128 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 bytes).
31805         // To generate a random key:  window.crypto.getRandomValues(new Uint8Array(16));
31806         // This default signing key is built into iD and can be used to mask/unmask sensitive values.
31807
31808         var DEFAULT_128 = [250, 157, 60, 79, 142, 134, 229, 129, 138, 126, 210, 129, 29, 71, 160, 208];
31809         function utilAesEncrypt(text, key) {
31810           key = key || DEFAULT_128;
31811           var textBytes = aesJs.utils.utf8.toBytes(text);
31812           var aesCtr = new aesJs.ModeOfOperation.ctr(key);
31813           var encryptedBytes = aesCtr.encrypt(textBytes);
31814           var encryptedHex = aesJs.utils.hex.fromBytes(encryptedBytes);
31815           return encryptedHex;
31816         }
31817         function utilAesDecrypt(encryptedHex, key) {
31818           key = key || DEFAULT_128;
31819           var encryptedBytes = aesJs.utils.hex.toBytes(encryptedHex);
31820           var aesCtr = new aesJs.ModeOfOperation.ctr(key);
31821           var decryptedBytes = aesCtr.decrypt(encryptedBytes);
31822           var text = aesJs.utils.utf8.fromBytes(decryptedBytes);
31823           return text;
31824         }
31825
31826         function utilCleanTags(tags) {
31827           var out = {};
31828
31829           for (var k in tags) {
31830             if (!k) continue;
31831             var v = tags[k];
31832
31833             if (v !== undefined) {
31834               out[k] = cleanValue(k, v);
31835             }
31836           }
31837
31838           return out;
31839
31840           function cleanValue(k, v) {
31841             function keepSpaces(k) {
31842               return /_hours|_times|:conditional$/.test(k);
31843             }
31844
31845             function skip(k) {
31846               return /^(description|note|fixme)$/.test(k);
31847             }
31848
31849             if (skip(k)) return v;
31850             var cleaned = v.split(';').map(function (s) {
31851               return s.trim();
31852             }).join(keepSpaces(k) ? '; ' : ';'); // The code below is not intended to validate websites and emails.
31853             // It is only intended to prevent obvious copy-paste errors. (#2323)
31854             // clean website- and email-like tags
31855
31856             if (k.indexOf('website') !== -1 || k.indexOf('email') !== -1 || cleaned.indexOf('http') === 0) {
31857               cleaned = cleaned.replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
31858             }
31859
31860             return cleaned;
31861           }
31862         }
31863
31864         var _detected;
31865
31866         function utilDetect(refresh) {
31867           if (_detected && !refresh) return _detected;
31868           _detected = {};
31869           var ua = navigator.userAgent;
31870           var m = null;
31871           /* Browser */
31872
31873           m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
31874
31875           if (m !== null) {
31876             _detected.browser = m[1];
31877             _detected.version = m[2];
31878           }
31879
31880           if (!_detected.browser) {
31881             m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
31882
31883             if (m !== null) {
31884               _detected.browser = 'msie';
31885               _detected.version = m[1];
31886             }
31887           }
31888
31889           if (!_detected.browser) {
31890             m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
31891
31892             if (m !== null) {
31893               _detected.browser = 'Opera';
31894               _detected.version = m[2];
31895             }
31896           }
31897
31898           if (!_detected.browser) {
31899             m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
31900
31901             if (m !== null) {
31902               _detected.browser = m[1];
31903               _detected.version = m[2];
31904               m = ua.match(/version\/([\.\d]+)/i);
31905               if (m !== null) _detected.version = m[1];
31906             }
31907           }
31908
31909           if (!_detected.browser) {
31910             _detected.browser = navigator.appName;
31911             _detected.version = navigator.appVersion;
31912           } // keep major.minor version only..
31913
31914
31915           _detected.version = _detected.version.split(/\W/).slice(0, 2).join('.'); // detect other browser capabilities
31916           // Legacy Opera has incomplete svg style support. See #715
31917
31918           _detected.opera = _detected.browser.toLowerCase() === 'opera' && parseFloat(_detected.version) < 15;
31919
31920           if (_detected.browser.toLowerCase() === 'msie') {
31921             _detected.ie = true;
31922             _detected.browser = 'Internet Explorer';
31923             _detected.support = parseFloat(_detected.version) >= 11;
31924           } else {
31925             _detected.ie = false;
31926             _detected.support = true;
31927           }
31928
31929           _detected.filedrop = window.FileReader && 'ondrop' in window;
31930           _detected.download = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
31931           _detected.cssfilters = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
31932           /* Platform */
31933
31934           if (/Win/.test(ua)) {
31935             _detected.os = 'win';
31936             _detected.platform = 'Windows';
31937           } else if (/Mac/.test(ua)) {
31938             _detected.os = 'mac';
31939             _detected.platform = 'Macintosh';
31940           } else if (/X11/.test(ua) || /Linux/.test(ua)) {
31941             _detected.os = 'linux';
31942             _detected.platform = 'Linux';
31943           } else {
31944             _detected.os = 'win';
31945             _detected.platform = 'Unknown';
31946           }
31947
31948           _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent,
31949           // so assume any "mac" with multitouch is actually iOS
31950           navigator.platform === 'MacIntel' && 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 1) && /WebKit/.test(ua) && !/Edge/.test(ua) && !window.MSStream;
31951           /* Locale */
31952           // An array of locales requested by the browser in priority order.
31953
31954           _detected.browserLocales = Array.from(new Set( // remove duplicates
31955           [navigator.language].concat(navigator.languages || []).concat([// old property for backwards compatibility
31956           navigator.userLanguage]) // remove any undefined values
31957           .filter(Boolean)));
31958           /* Host */
31959
31960           var loc = window.top.location;
31961           var origin = loc.origin;
31962
31963           if (!origin) {
31964             // for unpatched IE11
31965             origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port : '');
31966           }
31967
31968           _detected.host = origin + loc.pathname;
31969           return _detected;
31970         }
31971
31972         // Like selection.property('value', ...), but avoids no-op value sets,
31973         // which can result in layout/repaint thrashing in some situations.
31974         function utilGetSetValue(selection, value) {
31975           function d3_selection_value(value) {
31976             function valueNull() {
31977               delete this.value;
31978             }
31979
31980             function valueConstant() {
31981               if (this.value !== value) {
31982                 this.value = value;
31983               }
31984             }
31985
31986             function valueFunction() {
31987               var x = value.apply(this, arguments);
31988
31989               if (x === null || x === undefined) {
31990                 delete this.value;
31991               } else if (this.value !== x) {
31992                 this.value = x;
31993               }
31994             }
31995
31996             return value === null || value === undefined ? valueNull : typeof value === 'function' ? valueFunction : valueConstant;
31997           }
31998
31999           if (arguments.length === 1) {
32000             return selection.property('value');
32001           }
32002
32003           return selection.each(d3_selection_value(value));
32004         }
32005
32006         function utilKeybinding(namespace) {
32007           var _keybindings = {};
32008
32009           function testBindings(d3_event, isCapturing) {
32010             var didMatch = false;
32011             var bindings = Object.keys(_keybindings).map(function (id) {
32012               return _keybindings[id];
32013             });
32014             var i, binding; // Most key shortcuts will accept either lower or uppercase ('h' or 'H'),
32015             // so we don't strictly match on the shift key, but we prioritize
32016             // shifted keybindings first, and fallback to unshifted only if no match.
32017             // (This lets us differentiate between '←'/'⇧←' or '⌘Z'/'⌘⇧Z')
32018             // priority match shifted keybindings first
32019
32020             for (i = 0; i < bindings.length; i++) {
32021               binding = bindings[i];
32022               if (!binding.event.modifiers.shiftKey) continue; // no shift
32023
32024               if (!!binding.capture !== isCapturing) continue;
32025
32026               if (matches(d3_event, binding, true)) {
32027                 binding.callback(d3_event);
32028                 didMatch = true; // match a max of one binding per event
32029
32030                 break;
32031               }
32032             }
32033
32034             if (didMatch) return; // then unshifted keybindings
32035
32036             for (i = 0; i < bindings.length; i++) {
32037               binding = bindings[i];
32038               if (binding.event.modifiers.shiftKey) continue; // shift
32039
32040               if (!!binding.capture !== isCapturing) continue;
32041
32042               if (matches(d3_event, binding, false)) {
32043                 binding.callback(d3_event);
32044                 break;
32045               }
32046             }
32047
32048             function matches(d3_event, binding, testShift) {
32049               var event = d3_event;
32050               var isMatch = false;
32051               var tryKeyCode = true; // Prefer a match on `KeyboardEvent.key`
32052
32053               if (event.key !== undefined) {
32054                 tryKeyCode = event.key.charCodeAt(0) > 255; // outside ISO-Latin-1
32055
32056                 isMatch = true;
32057
32058                 if (binding.event.key === undefined) {
32059                   isMatch = false;
32060                 } else if (Array.isArray(binding.event.key)) {
32061                   if (binding.event.key.map(function (s) {
32062                     return s.toLowerCase();
32063                   }).indexOf(event.key.toLowerCase()) === -1) {
32064                     isMatch = false;
32065                   }
32066                 } else {
32067                   if (event.key.toLowerCase() !== binding.event.key.toLowerCase()) {
32068                     isMatch = false;
32069                   }
32070                 }
32071               } // Fallback match on `KeyboardEvent.keyCode`, can happen if:
32072               // - browser doesn't support `KeyboardEvent.key`
32073               // - `KeyboardEvent.key` is outside ISO-Latin-1 range (cyrillic?)
32074
32075
32076               if (!isMatch && tryKeyCode) {
32077                 isMatch = event.keyCode === binding.event.keyCode;
32078               }
32079
32080               if (!isMatch) return false; // test modifier keys
32081
32082               if (!(event.ctrlKey && event.altKey)) {
32083                 // if both are set, assume AltGr and skip it - #4096
32084                 if (event.ctrlKey !== binding.event.modifiers.ctrlKey) return false;
32085                 if (event.altKey !== binding.event.modifiers.altKey) return false;
32086               }
32087
32088               if (event.metaKey !== binding.event.modifiers.metaKey) return false;
32089               if (testShift && event.shiftKey !== binding.event.modifiers.shiftKey) return false;
32090               return true;
32091             }
32092           }
32093
32094           function capture(d3_event) {
32095             testBindings(d3_event, true);
32096           }
32097
32098           function bubble(d3_event) {
32099             var tagName = select(d3_event.target).node().tagName;
32100
32101             if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
32102               return;
32103             }
32104
32105             testBindings(d3_event, false);
32106           }
32107
32108           function keybinding(selection) {
32109             selection = selection || select(document);
32110             selection.on('keydown.capture.' + namespace, capture, true);
32111             selection.on('keydown.bubble.' + namespace, bubble, false);
32112             return keybinding;
32113           } // was: keybinding.off()
32114
32115
32116           keybinding.unbind = function (selection) {
32117             _keybindings = [];
32118             selection = selection || select(document);
32119             selection.on('keydown.capture.' + namespace, null);
32120             selection.on('keydown.bubble.' + namespace, null);
32121             return keybinding;
32122           };
32123
32124           keybinding.clear = function () {
32125             _keybindings = {};
32126             return keybinding;
32127           }; // Remove one or more keycode bindings.
32128
32129
32130           keybinding.off = function (codes, capture) {
32131             var arr = utilArrayUniq([].concat(codes));
32132
32133             for (var i = 0; i < arr.length; i++) {
32134               var id = arr[i] + (capture ? '-capture' : '-bubble');
32135               delete _keybindings[id];
32136             }
32137
32138             return keybinding;
32139           }; // Add one or more keycode bindings.
32140
32141
32142           keybinding.on = function (codes, callback, capture) {
32143             if (typeof callback !== 'function') {
32144               return keybinding.off(codes, capture);
32145             }
32146
32147             var arr = utilArrayUniq([].concat(codes));
32148
32149             for (var i = 0; i < arr.length; i++) {
32150               var id = arr[i] + (capture ? '-capture' : '-bubble');
32151               var binding = {
32152                 id: id,
32153                 capture: capture,
32154                 callback: callback,
32155                 event: {
32156                   key: undefined,
32157                   // preferred
32158                   keyCode: 0,
32159                   // fallback
32160                   modifiers: {
32161                     shiftKey: false,
32162                     ctrlKey: false,
32163                     altKey: false,
32164                     metaKey: false
32165                   }
32166                 }
32167               };
32168
32169               if (_keybindings[id]) {
32170                 console.warn('warning: duplicate keybinding for "' + id + '"'); // eslint-disable-line no-console
32171               }
32172
32173               _keybindings[id] = binding;
32174               var matches = arr[i].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
32175
32176               for (var j = 0; j < matches.length; j++) {
32177                 // Normalise matching errors
32178                 if (matches[j] === '++') matches[j] = '+';
32179
32180                 if (matches[j] in utilKeybinding.modifierCodes) {
32181                   var prop = utilKeybinding.modifierProperties[utilKeybinding.modifierCodes[matches[j]]];
32182                   binding.event.modifiers[prop] = true;
32183                 } else {
32184                   binding.event.key = utilKeybinding.keys[matches[j]] || matches[j];
32185
32186                   if (matches[j] in utilKeybinding.keyCodes) {
32187                     binding.event.keyCode = utilKeybinding.keyCodes[matches[j]];
32188                   }
32189                 }
32190               }
32191             }
32192
32193             return keybinding;
32194           };
32195
32196           return keybinding;
32197         }
32198         /*
32199          * See https://github.com/keithamus/jwerty
32200          */
32201
32202         utilKeybinding.modifierCodes = {
32203           // Shift key, ⇧
32204           '⇧': 16,
32205           shift: 16,
32206           // CTRL key, on Mac: ⌃
32207           '⌃': 17,
32208           ctrl: 17,
32209           // ALT key, on Mac: ⌥ (Alt)
32210           '⌥': 18,
32211           alt: 18,
32212           option: 18,
32213           // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
32214           '⌘': 91,
32215           meta: 91,
32216           cmd: 91,
32217           'super': 91,
32218           win: 91
32219         };
32220         utilKeybinding.modifierProperties = {
32221           16: 'shiftKey',
32222           17: 'ctrlKey',
32223           18: 'altKey',
32224           91: 'metaKey'
32225         };
32226         utilKeybinding.plusKeys = ['plus', 'ffplus', '=', 'ffequals', '≠', '±'];
32227         utilKeybinding.minusKeys = ['_', '-', 'ffminus', 'dash', '–', '—'];
32228         utilKeybinding.keys = {
32229           // Backspace key, on Mac: ⌫ (Backspace)
32230           '⌫': 'Backspace',
32231           backspace: 'Backspace',
32232           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
32233           '⇥': 'Tab',
32234           '⇆': 'Tab',
32235           tab: 'Tab',
32236           // Return key, ↩
32237           '↩': 'Enter',
32238           '↵': 'Enter',
32239           '⏎': 'Enter',
32240           'return': 'Enter',
32241           enter: 'Enter',
32242           '⌅': 'Enter',
32243           // Pause/Break key
32244           'pause': 'Pause',
32245           'pause-break': 'Pause',
32246           // Caps Lock key, ⇪
32247           '⇪': 'CapsLock',
32248           caps: 'CapsLock',
32249           'caps-lock': 'CapsLock',
32250           // Escape key, on Mac: ⎋, on Windows: Esc
32251           '⎋': ['Escape', 'Esc'],
32252           escape: ['Escape', 'Esc'],
32253           esc: ['Escape', 'Esc'],
32254           // Space key
32255           space: [' ', 'Spacebar'],
32256           // Page-Up key, or pgup, on Mac: ↖
32257           '↖': 'PageUp',
32258           pgup: 'PageUp',
32259           'page-up': 'PageUp',
32260           // Page-Down key, or pgdown, on Mac: ↘
32261           '↘': 'PageDown',
32262           pgdown: 'PageDown',
32263           'page-down': 'PageDown',
32264           // END key, on Mac: ⇟
32265           '⇟': 'End',
32266           end: 'End',
32267           // HOME key, on Mac: ⇞
32268           '⇞': 'Home',
32269           home: 'Home',
32270           // Insert key, or ins
32271           ins: 'Insert',
32272           insert: 'Insert',
32273           // Delete key, on Mac: ⌦ (Delete)
32274           '⌦': ['Delete', 'Del'],
32275           del: ['Delete', 'Del'],
32276           'delete': ['Delete', 'Del'],
32277           // Left Arrow Key, or ←
32278           '←': ['ArrowLeft', 'Left'],
32279           left: ['ArrowLeft', 'Left'],
32280           'arrow-left': ['ArrowLeft', 'Left'],
32281           // Up Arrow Key, or ↑
32282           '↑': ['ArrowUp', 'Up'],
32283           up: ['ArrowUp', 'Up'],
32284           'arrow-up': ['ArrowUp', 'Up'],
32285           // Right Arrow Key, or →
32286           '→': ['ArrowRight', 'Right'],
32287           right: ['ArrowRight', 'Right'],
32288           'arrow-right': ['ArrowRight', 'Right'],
32289           // Up Arrow Key, or ↓
32290           '↓': ['ArrowDown', 'Down'],
32291           down: ['ArrowDown', 'Down'],
32292           'arrow-down': ['ArrowDown', 'Down'],
32293           // odities, stuff for backward compatibility (browsers and code):
32294           // Num-Multiply, or *
32295           '*': ['*', 'Multiply'],
32296           star: ['*', 'Multiply'],
32297           asterisk: ['*', 'Multiply'],
32298           multiply: ['*', 'Multiply'],
32299           // Num-Plus or +
32300           '+': ['+', 'Add'],
32301           'plus': ['+', 'Add'],
32302           // Num-Subtract, or -
32303           '-': ['-', 'Subtract'],
32304           subtract: ['-', 'Subtract'],
32305           'dash': ['-', 'Subtract'],
32306           // Semicolon
32307           semicolon: ';',
32308           // = or equals
32309           equals: '=',
32310           // Comma, or ,
32311           comma: ',',
32312           // Period, or ., or full-stop
32313           period: '.',
32314           'full-stop': '.',
32315           // Slash, or /, or forward-slash
32316           slash: '/',
32317           'forward-slash': '/',
32318           // Tick, or `, or back-quote
32319           tick: '`',
32320           'back-quote': '`',
32321           // Open bracket, or [
32322           'open-bracket': '[',
32323           // Back slash, or \
32324           'back-slash': '\\',
32325           // Close backet, or ]
32326           'close-bracket': ']',
32327           // Apostrophe, or Quote, or '
32328           quote: '\'',
32329           apostrophe: '\'',
32330           // NUMPAD 0-9
32331           'num-0': '0',
32332           'num-1': '1',
32333           'num-2': '2',
32334           'num-3': '3',
32335           'num-4': '4',
32336           'num-5': '5',
32337           'num-6': '6',
32338           'num-7': '7',
32339           'num-8': '8',
32340           'num-9': '9',
32341           // F1-F25
32342           f1: 'F1',
32343           f2: 'F2',
32344           f3: 'F3',
32345           f4: 'F4',
32346           f5: 'F5',
32347           f6: 'F6',
32348           f7: 'F7',
32349           f8: 'F8',
32350           f9: 'F9',
32351           f10: 'F10',
32352           f11: 'F11',
32353           f12: 'F12',
32354           f13: 'F13',
32355           f14: 'F14',
32356           f15: 'F15',
32357           f16: 'F16',
32358           f17: 'F17',
32359           f18: 'F18',
32360           f19: 'F19',
32361           f20: 'F20',
32362           f21: 'F21',
32363           f22: 'F22',
32364           f23: 'F23',
32365           f24: 'F24',
32366           f25: 'F25'
32367         };
32368         utilKeybinding.keyCodes = {
32369           // Backspace key, on Mac: ⌫ (Backspace)
32370           '⌫': 8,
32371           backspace: 8,
32372           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
32373           '⇥': 9,
32374           '⇆': 9,
32375           tab: 9,
32376           // Return key, ↩
32377           '↩': 13,
32378           '↵': 13,
32379           '⏎': 13,
32380           'return': 13,
32381           enter: 13,
32382           '⌅': 13,
32383           // Pause/Break key
32384           'pause': 19,
32385           'pause-break': 19,
32386           // Caps Lock key, ⇪
32387           '⇪': 20,
32388           caps: 20,
32389           'caps-lock': 20,
32390           // Escape key, on Mac: ⎋, on Windows: Esc
32391           '⎋': 27,
32392           escape: 27,
32393           esc: 27,
32394           // Space key
32395           space: 32,
32396           // Page-Up key, or pgup, on Mac: ↖
32397           '↖': 33,
32398           pgup: 33,
32399           'page-up': 33,
32400           // Page-Down key, or pgdown, on Mac: ↘
32401           '↘': 34,
32402           pgdown: 34,
32403           'page-down': 34,
32404           // END key, on Mac: ⇟
32405           '⇟': 35,
32406           end: 35,
32407           // HOME key, on Mac: ⇞
32408           '⇞': 36,
32409           home: 36,
32410           // Insert key, or ins
32411           ins: 45,
32412           insert: 45,
32413           // Delete key, on Mac: ⌦ (Delete)
32414           '⌦': 46,
32415           del: 46,
32416           'delete': 46,
32417           // Left Arrow Key, or ←
32418           '←': 37,
32419           left: 37,
32420           'arrow-left': 37,
32421           // Up Arrow Key, or ↑
32422           '↑': 38,
32423           up: 38,
32424           'arrow-up': 38,
32425           // Right Arrow Key, or →
32426           '→': 39,
32427           right: 39,
32428           'arrow-right': 39,
32429           // Up Arrow Key, or ↓
32430           '↓': 40,
32431           down: 40,
32432           'arrow-down': 40,
32433           // odities, printing characters that come out wrong:
32434           // Firefox Equals
32435           'ffequals': 61,
32436           // Num-Multiply, or *
32437           '*': 106,
32438           star: 106,
32439           asterisk: 106,
32440           multiply: 106,
32441           // Num-Plus or +
32442           '+': 107,
32443           'plus': 107,
32444           // Num-Subtract, or -
32445           '-': 109,
32446           subtract: 109,
32447           // Vertical Bar / Pipe
32448           '|': 124,
32449           // Firefox Plus
32450           'ffplus': 171,
32451           // Firefox Minus
32452           'ffminus': 173,
32453           // Semicolon
32454           ';': 186,
32455           semicolon: 186,
32456           // = or equals
32457           '=': 187,
32458           'equals': 187,
32459           // Comma, or ,
32460           ',': 188,
32461           comma: 188,
32462           // Dash / Underscore key
32463           'dash': 189,
32464           // Period, or ., or full-stop
32465           '.': 190,
32466           period: 190,
32467           'full-stop': 190,
32468           // Slash, or /, or forward-slash
32469           '/': 191,
32470           slash: 191,
32471           'forward-slash': 191,
32472           // Tick, or `, or back-quote
32473           '`': 192,
32474           tick: 192,
32475           'back-quote': 192,
32476           // Open bracket, or [
32477           '[': 219,
32478           'open-bracket': 219,
32479           // Back slash, or \
32480           '\\': 220,
32481           'back-slash': 220,
32482           // Close backet, or ]
32483           ']': 221,
32484           'close-bracket': 221,
32485           // Apostrophe, or Quote, or '
32486           '\'': 222,
32487           quote: 222,
32488           apostrophe: 222
32489         }; // NUMPAD 0-9
32490
32491         var i = 95,
32492             n = 0;
32493
32494         while (++i < 106) {
32495           utilKeybinding.keyCodes['num-' + n] = i;
32496           ++n;
32497         } // 0-9
32498
32499
32500         i = 47;
32501         n = 0;
32502
32503         while (++i < 58) {
32504           utilKeybinding.keyCodes[n] = i;
32505           ++n;
32506         } // F1-F25
32507
32508
32509         i = 111;
32510         n = 1;
32511
32512         while (++i < 136) {
32513           utilKeybinding.keyCodes['f' + n] = i;
32514           ++n;
32515         } // a-z
32516
32517
32518         i = 64;
32519
32520         while (++i < 91) {
32521           utilKeybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i;
32522         }
32523
32524         function utilObjectOmit(obj, omitKeys) {
32525           return Object.keys(obj).reduce(function (result, key) {
32526             if (omitKeys.indexOf(key) === -1) {
32527               result[key] = obj[key]; // keep
32528             }
32529
32530             return result;
32531           }, {});
32532         }
32533
32534         // Copies a variable number of methods from source to target.
32535         function utilRebind(target, source) {
32536           var i = 1,
32537               n = arguments.length,
32538               method;
32539
32540           while (++i < n) {
32541             target[method = arguments[i]] = d3_rebind(target, source, source[method]);
32542           }
32543
32544           return target;
32545         } // Method is assumed to be a standard D3 getter-setter:
32546         // If passed with no arguments, gets the value.
32547         // If passed with arguments, sets the value and returns the target.
32548
32549         function d3_rebind(target, source, method) {
32550           return function () {
32551             var value = method.apply(source, arguments);
32552             return value === source ? target : value;
32553           };
32554         }
32555
32556         // A per-domain session mutex backed by a cookie and dead man's
32557         // switch. If the session crashes, the mutex will auto-release
32558         // after 5 seconds.
32559         // This accepts a string and returns an object that complies with utilSessionMutexType
32560         function utilSessionMutex(name) {
32561           var mutex = {};
32562           var intervalID;
32563
32564           function renew() {
32565             var expires = new Date();
32566             expires.setSeconds(expires.getSeconds() + 5);
32567             document.cookie = name + '=1; expires=' + expires.toUTCString() + '; sameSite=strict';
32568           }
32569
32570           mutex.lock = function () {
32571             if (intervalID) return true;
32572             var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
32573             if (cookie) return false;
32574             renew();
32575             intervalID = window.setInterval(renew, 4000);
32576             return true;
32577           };
32578
32579           mutex.unlock = function () {
32580             if (!intervalID) return;
32581             document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; sameSite=strict';
32582             clearInterval(intervalID);
32583             intervalID = null;
32584           };
32585
32586           mutex.locked = function () {
32587             return !!intervalID;
32588           };
32589
32590           return mutex;
32591         }
32592
32593         function utilTiler() {
32594           var _size = [256, 256];
32595           var _scale = 256;
32596           var _tileSize = 256;
32597           var _zoomExtent = [0, 20];
32598           var _translate = [_size[0] / 2, _size[1] / 2];
32599           var _margin = 0;
32600           var _skipNullIsland = false;
32601
32602           function clamp(num, min, max) {
32603             return Math.max(min, Math.min(num, max));
32604           }
32605
32606           function nearNullIsland(tile) {
32607             var x = tile[0];
32608             var y = tile[1];
32609             var z = tile[2];
32610
32611             if (z >= 7) {
32612               var center = Math.pow(2, z - 1);
32613               var width = Math.pow(2, z - 6);
32614               var min = center - width / 2;
32615               var max = center + width / 2 - 1;
32616               return x >= min && x <= max && y >= min && y <= max;
32617             }
32618
32619             return false;
32620           }
32621
32622           function tiler() {
32623             var z = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
32624             var z0 = clamp(Math.round(z), _zoomExtent[0], _zoomExtent[1]);
32625             var tileMin = 0;
32626             var tileMax = Math.pow(2, z0) - 1;
32627             var log2ts = Math.log(_tileSize) * Math.LOG2E;
32628             var k = Math.pow(2, z - z0 + log2ts);
32629             var origin = [(_translate[0] - _scale / 2) / k, (_translate[1] - _scale / 2) / k];
32630             var cols = range$1(clamp(Math.floor(-origin[0]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[0] / k - origin[0]) + _margin, tileMin, tileMax + 1));
32631             var rows = range$1(clamp(Math.floor(-origin[1]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[1] / k - origin[1]) + _margin, tileMin, tileMax + 1));
32632             var tiles = [];
32633
32634             for (var i = 0; i < rows.length; i++) {
32635               var y = rows[i];
32636
32637               for (var j = 0; j < cols.length; j++) {
32638                 var x = cols[j];
32639
32640                 if (i >= _margin && i <= rows.length - _margin && j >= _margin && j <= cols.length - _margin) {
32641                   tiles.unshift([x, y, z0]); // tiles in view at beginning
32642                 } else {
32643                   tiles.push([x, y, z0]); // tiles in margin at the end
32644                 }
32645               }
32646             }
32647
32648             tiles.translate = origin;
32649             tiles.scale = k;
32650             return tiles;
32651           }
32652           /**
32653            * getTiles() returns an array of tiles that cover the map view
32654            */
32655
32656
32657           tiler.getTiles = function (projection) {
32658             var origin = [projection.scale() * Math.PI - projection.translate()[0], projection.scale() * Math.PI - projection.translate()[1]];
32659             this.size(projection.clipExtent()[1]).scale(projection.scale() * 2 * Math.PI).translate(projection.translate());
32660             var tiles = tiler();
32661             var ts = tiles.scale;
32662             return tiles.map(function (tile) {
32663               if (_skipNullIsland && nearNullIsland(tile)) {
32664                 return false;
32665               }
32666
32667               var x = tile[0] * ts - origin[0];
32668               var y = tile[1] * ts - origin[1];
32669               return {
32670                 id: tile.toString(),
32671                 xyz: tile,
32672                 extent: geoExtent(projection.invert([x, y + ts]), projection.invert([x + ts, y]))
32673               };
32674             }).filter(Boolean);
32675           };
32676           /**
32677            * getGeoJSON() returns a FeatureCollection for debugging tiles
32678            */
32679
32680
32681           tiler.getGeoJSON = function (projection) {
32682             var features = tiler.getTiles(projection).map(function (tile) {
32683               return {
32684                 type: 'Feature',
32685                 properties: {
32686                   id: tile.id,
32687                   name: tile.id
32688                 },
32689                 geometry: {
32690                   type: 'Polygon',
32691                   coordinates: [tile.extent.polygon()]
32692                 }
32693               };
32694             });
32695             return {
32696               type: 'FeatureCollection',
32697               features: features
32698             };
32699           };
32700
32701           tiler.tileSize = function (val) {
32702             if (!arguments.length) return _tileSize;
32703             _tileSize = val;
32704             return tiler;
32705           };
32706
32707           tiler.zoomExtent = function (val) {
32708             if (!arguments.length) return _zoomExtent;
32709             _zoomExtent = val;
32710             return tiler;
32711           };
32712
32713           tiler.size = function (val) {
32714             if (!arguments.length) return _size;
32715             _size = val;
32716             return tiler;
32717           };
32718
32719           tiler.scale = function (val) {
32720             if (!arguments.length) return _scale;
32721             _scale = val;
32722             return tiler;
32723           };
32724
32725           tiler.translate = function (val) {
32726             if (!arguments.length) return _translate;
32727             _translate = val;
32728             return tiler;
32729           }; // number to extend the rows/columns beyond those covering the viewport
32730
32731
32732           tiler.margin = function (val) {
32733             if (!arguments.length) return _margin;
32734             _margin = +val;
32735             return tiler;
32736           };
32737
32738           tiler.skipNullIsland = function (val) {
32739             if (!arguments.length) return _skipNullIsland;
32740             _skipNullIsland = val;
32741             return tiler;
32742           };
32743
32744           return tiler;
32745         }
32746
32747         function utilTriggerEvent(target, type) {
32748           target.each(function () {
32749             var evt = document.createEvent('HTMLEvents');
32750             evt.initEvent(type, true, true);
32751             this.dispatchEvent(evt);
32752           });
32753         }
32754
32755         var _mainLocations = coreLocations(); // singleton
32756         // `coreLocations` maintains an internal index of all the boundaries/geofences used by iD.
32757         // It's used by presets, community index, background imagery, to know where in the world these things are valid.
32758         // These geofences should be defined by `locationSet` objects:
32759         //
32760         // let locationSet = {
32761         //   include: [ Array of locations ],
32762         //   exclude: [ Array of locations ]
32763         // };
32764         //
32765         // For more info see the location-conflation and country-coder projects, see:
32766         // https://github.com/ideditor/location-conflation
32767         // https://github.com/ideditor/country-coder
32768         //
32769
32770         function coreLocations() {
32771           var _this = {};
32772           var _resolvedFeatures = {}; // cache of *resolved* locationSet features
32773
32774           var _loco = new _default(); // instance of a location-conflation resolver
32775
32776
32777           var _wp; // instance of a which-polygon index
32778           // pre-resolve the worldwide locationSet
32779
32780
32781           var world = {
32782             locationSet: {
32783               include: ['Q2']
32784             }
32785           };
32786           resolveLocationSet(world);
32787           rebuildIndex();
32788           var _queue = [];
32789
32790           var _deferred = new Set();
32791
32792           var _inProcess; // Returns a Promise to process the queue
32793
32794
32795           function processQueue() {
32796             if (!_queue.length) return Promise.resolve(); // console.log(`queue length ${_queue.length}`);
32797
32798             var chunk = _queue.pop();
32799
32800             return new Promise(function (resolvePromise) {
32801               var handle = window.requestIdleCallback(function () {
32802                 _deferred["delete"](handle); // const t0 = performance.now();
32803
32804
32805                 chunk.forEach(resolveLocationSet); // const t1 = performance.now();
32806                 // console.log('chunk processed in ' + (t1 - t0) + ' ms');
32807
32808                 resolvePromise();
32809               });
32810
32811               _deferred.add(handle);
32812             }).then(function () {
32813               return processQueue();
32814             });
32815           } // Pass an Object with a `locationSet` property,
32816           // Performs the locationSet resolution, caches the result, and sets a `locationSetID` property on the object.
32817
32818
32819           function resolveLocationSet(obj) {
32820             if (obj.locationSetID) return; // work was done already
32821
32822             try {
32823               var locationSet = obj.locationSet;
32824
32825               if (!locationSet) {
32826                 throw new Error('object missing locationSet property');
32827               }
32828
32829               if (!locationSet.include) {
32830                 // missing `include`, default to worldwide include
32831                 locationSet.include = ['Q2']; // https://github.com/openstreetmap/iD/pull/8305#discussion_r662344647
32832               }
32833
32834               var resolved = _loco.resolveLocationSet(locationSet);
32835
32836               var locationSetID = resolved.id;
32837               obj.locationSetID = locationSetID;
32838
32839               if (!resolved.feature.geometry.coordinates.length || !resolved.feature.properties.area) {
32840                 throw new Error("locationSet ".concat(locationSetID, " resolves to an empty feature."));
32841               }
32842
32843               if (!_resolvedFeatures[locationSetID]) {
32844                 // First time seeing this locationSet feature
32845                 var feature = JSON.parse(JSON.stringify(resolved.feature)); // deep clone
32846
32847                 feature.id = locationSetID; // Important: always use the locationSet `id` (`+[Q30]`), not the feature `id` (`Q30`)
32848
32849                 feature.properties.id = locationSetID;
32850                 _resolvedFeatures[locationSetID] = feature; // insert into cache
32851               }
32852             } catch (err) {
32853               obj.locationSet = {
32854                 include: ['Q2']
32855               }; // default worldwide
32856
32857               obj.locationSetID = '+[Q2]';
32858             }
32859           } // Rebuilds the whichPolygon index with whatever features have been resolved.
32860
32861
32862           function rebuildIndex() {
32863             _wp = whichPolygon_1({
32864               features: Object.values(_resolvedFeatures)
32865             });
32866           } //
32867           // `mergeCustomGeoJSON`
32868           //  Accepts an FeatureCollection-like object containing custom locations
32869           //  Each feature must have a filename-like `id`, for example: `something.geojson`
32870           //
32871           //  {
32872           //    "type": "FeatureCollection"
32873           //    "features": [
32874           //      {
32875           //        "type": "Feature",
32876           //        "id": "philly_metro.geojson",
32877           //        "properties": { … },
32878           //        "geometry": { … }
32879           //      }
32880           //    ]
32881           //  }
32882           //
32883
32884
32885           _this.mergeCustomGeoJSON = function (fc) {
32886             if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
32887               fc.features.forEach(function (feature) {
32888                 feature.properties = feature.properties || {};
32889                 var props = feature.properties; // Get `id` from either `id` or `properties`
32890
32891                 var id = feature.id || props.id;
32892                 if (!id || !/^\S+\.geojson$/i.test(id)) return; // Ensure `id` exists and is lowercase
32893
32894                 id = id.toLowerCase();
32895                 feature.id = id;
32896                 props.id = id; // Ensure `area` property exists
32897
32898                 if (!props.area) {
32899                   var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
32900
32901                   props.area = Number(area.toFixed(2));
32902                 }
32903
32904                 _loco._cache[id] = feature;
32905               });
32906             }
32907           }; //
32908           // `mergeLocationSets`
32909           //  Accepts an Array of Objects containing `locationSet` properties.
32910           //  The locationSets will be resolved and indexed in the background.
32911           //  [
32912           //   { id: 'preset1', locationSet: {…} },
32913           //   { id: 'preset2', locationSet: {…} },
32914           //   { id: 'preset3', locationSet: {…} },
32915           //   …
32916           //  ]
32917           //  After resolving and indexing, the Objects will be decorated with a
32918           //  `locationSetID` property.
32919           //  [
32920           //   { id: 'preset1', locationSet: {…}, locationSetID: '+[Q2]' },
32921           //   { id: 'preset2', locationSet: {…}, locationSetID: '+[Q30]' },
32922           //   { id: 'preset3', locationSet: {…}, locationSetID: '+[Q2]' },
32923           //   …
32924           //  ]
32925           //
32926           //  Returns a Promise fulfilled when the resolving/indexing has been completed
32927           //  This will take some seconds but happen in the background during browser idle time.
32928           //
32929
32930
32931           _this.mergeLocationSets = function (objects) {
32932             if (!Array.isArray(objects)) return Promise.reject('nothing to do'); // Resolve all locationSets -> geojson, processing data in chunks
32933             //
32934             // Because this will happen during idle callbacks, we want to choose a chunk size
32935             // that won't make the browser stutter too badly.  LocationSets that are a simple
32936             // country coder include will resolve instantly, but ones that involve complex
32937             // include/exclude operations will take some milliseconds longer.
32938             //
32939             // Some discussion and performance results on these tickets:
32940             // https://github.com/ideditor/location-conflation/issues/26
32941             // https://github.com/osmlab/name-suggestion-index/issues/4784#issuecomment-742003434
32942
32943             _queue = _queue.concat(utilArrayChunk(objects, 200));
32944
32945             if (!_inProcess) {
32946               _inProcess = processQueue().then(function () {
32947                 rebuildIndex();
32948                 _inProcess = null;
32949                 return objects;
32950               });
32951             }
32952
32953             return _inProcess;
32954           }; //
32955           // `locationSetID`
32956           // Returns a locationSetID for a given locationSet (fallback to `+[Q2]`, world)
32957           // (The locationset doesn't necessarily need to be resolved to compute its `id`)
32958           //
32959           // Arguments
32960           //   `locationSet`: A locationSet, e.g. `{ include: ['us'] }`
32961           // Returns
32962           //   The locationSetID, e.g. `+[Q30]`
32963           //
32964
32965
32966           _this.locationSetID = function (locationSet) {
32967             var locationSetID;
32968
32969             try {
32970               locationSetID = _loco.validateLocationSet(locationSet).id;
32971             } catch (err) {
32972               locationSetID = '+[Q2]'; // the world
32973             }
32974
32975             return locationSetID;
32976           }; //
32977           // `feature`
32978           // Returns the resolved GeoJSON feature for a given locationSetID (fallback to 'world')
32979           //
32980           // Arguments
32981           //   `locationSetID`: id of the form like `+[Q30]`  (United States)
32982           // Returns
32983           //   A GeoJSON feature:
32984           //   {
32985           //     type: 'Feature',
32986           //     id: '+[Q30]',
32987           //     properties: { id: '+[Q30]', area: 21817019.17, … },
32988           //     geometry: { … }
32989           //   }
32990
32991
32992           _this.feature = function (locationSetID) {
32993             return _resolvedFeatures[locationSetID] || _resolvedFeatures['+[Q2]'];
32994           }; //
32995           // `locationsAt`
32996           // Find all the resolved locationSets valid at the given location.
32997           // Results include the area (in km²) to facilitate sorting.
32998           //
32999           // Arguments
33000           //   `loc`: the [lon,lat] location to query, e.g. `[-74.4813, 40.7967]`
33001           // Returns
33002           //   Object of locationSetIDs to areas (in km²)
33003           //   {
33004           //     "+[Q2]": 511207893.3958111,
33005           //     "+[Q30]": 21817019.17,
33006           //     "+[new_jersey.geojson]": 22390.77,
33007           //     …
33008           //   }
33009           //
33010
33011
33012           _this.locationsAt = function (loc) {
33013             var result = {};
33014             (_wp(loc, true) || []).forEach(function (prop) {
33015               return result[prop.id] = prop.area;
33016             });
33017             return result;
33018           }; //
33019           // `query`
33020           // Execute a query directly against which-polygon
33021           // https://github.com/mapbox/which-polygon
33022           //
33023           // Arguments
33024           //   `loc`: the [lon,lat] location to query,
33025           //   `multi`: `true` to return all results, `false` to return first result
33026           // Returns
33027           //   Array of GeoJSON *properties* for the locationSet features that exist at `loc`
33028           //
33029
33030
33031           _this.query = function (loc, multi) {
33032             return _wp(loc, multi);
33033           }; // Direct access to the location-conflation resolver
33034
33035
33036           _this.loco = function () {
33037             return _loco;
33038           }; // Direct access to the which-polygon index
33039
33040
33041           _this.wp = function () {
33042             return _wp;
33043           };
33044
33045           return _this;
33046         }
33047
33048         var $findIndex = arrayIteration.findIndex;
33049
33050
33051         var FIND_INDEX = 'findIndex';
33052         var SKIPS_HOLES = true;
33053
33054         // Shouldn't skip holes
33055         if (FIND_INDEX in []) Array(1)[FIND_INDEX](function () { SKIPS_HOLES = false; });
33056
33057         // `Array.prototype.findIndex` method
33058         // https://tc39.es/ecma262/#sec-array.prototype.findindex
33059         _export({ target: 'Array', proto: true, forced: SKIPS_HOLES }, {
33060           findIndex: function findIndex(callbackfn /* , that = undefined */) {
33061             return $findIndex(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
33062           }
33063         });
33064
33065         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
33066         addToUnscopables(FIND_INDEX);
33067
33068         var notARegexp = function (it) {
33069           if (isRegexp(it)) {
33070             throw TypeError("The method doesn't accept regular expressions");
33071           } return it;
33072         };
33073
33074         var MATCH = wellKnownSymbol('match');
33075
33076         var correctIsRegexpLogic = function (METHOD_NAME) {
33077           var regexp = /./;
33078           try {
33079             '/./'[METHOD_NAME](regexp);
33080           } catch (error1) {
33081             try {
33082               regexp[MATCH] = false;
33083               return '/./'[METHOD_NAME](regexp);
33084             } catch (error2) { /* empty */ }
33085           } return false;
33086         };
33087
33088         // `String.prototype.includes` method
33089         // https://tc39.es/ecma262/#sec-string.prototype.includes
33090         _export({ target: 'String', proto: true, forced: !correctIsRegexpLogic('includes') }, {
33091           includes: function includes(searchString /* , position = 0 */) {
33092             return !!~String(requireObjectCoercible(this))
33093               .indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined);
33094           }
33095         });
33096
33097         var _mainLocalizer = coreLocalizer(); // singleton
33098
33099
33100         var _t = _mainLocalizer.t;
33101         // coreLocalizer manages language and locale parameters including translated strings
33102         //
33103
33104         function coreLocalizer() {
33105           var localizer = {};
33106           var _dataLanguages = {}; // `_dataLocales` is an object containing all _supported_ locale codes -> language info.
33107           // * `rtl` - right-to-left or left-to-right text direction
33108           // * `pct` - the percent of strings translated; 1 = 100%, full coverage
33109           //
33110           // {
33111           // en: { rtl: false, pct: {…} },
33112           // de: { rtl: false, pct: {…} },
33113           // …
33114           // }
33115
33116           var _dataLocales = {}; // `localeStrings` is an object containing all _loaded_ locale codes -> string data.
33117           // {
33118           // en: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
33119           // de: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
33120           // …
33121           // }
33122
33123           var _localeStrings = {}; // the current locale
33124
33125           var _localeCode = 'en-US'; // `_localeCodes` must contain `_localeCode` first, optionally followed by fallbacks
33126
33127           var _localeCodes = ['en-US', 'en'];
33128           var _languageCode = 'en';
33129           var _textDirection = 'ltr';
33130           var _usesMetric = false;
33131           var _languageNames = {};
33132           var _scriptNames = {}; // getters for the current locale parameters
33133
33134           localizer.localeCode = function () {
33135             return _localeCode;
33136           };
33137
33138           localizer.localeCodes = function () {
33139             return _localeCodes;
33140           };
33141
33142           localizer.languageCode = function () {
33143             return _languageCode;
33144           };
33145
33146           localizer.textDirection = function () {
33147             return _textDirection;
33148           };
33149
33150           localizer.usesMetric = function () {
33151             return _usesMetric;
33152           };
33153
33154           localizer.languageNames = function () {
33155             return _languageNames;
33156           };
33157
33158           localizer.scriptNames = function () {
33159             return _scriptNames;
33160           }; // The client app may want to manually set the locale, regardless of the
33161           // settings provided by the browser
33162
33163
33164           var _preferredLocaleCodes = [];
33165
33166           localizer.preferredLocaleCodes = function (codes) {
33167             if (!arguments.length) return _preferredLocaleCodes;
33168
33169             if (typeof codes === 'string') {
33170               // be generous and accept delimited strings as input
33171               _preferredLocaleCodes = codes.split(/,|;| /gi).filter(Boolean);
33172             } else {
33173               _preferredLocaleCodes = codes;
33174             }
33175
33176             return localizer;
33177           };
33178
33179           var _loadPromise;
33180
33181           localizer.ensureLoaded = function () {
33182             if (_loadPromise) return _loadPromise;
33183             var filesToFetch = [// load the list of languages
33184             'languages', // load the list of supported locales
33185             'locales'];
33186             var localeDirs = {
33187               general: 'locales',
33188               tagging: 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/translations'
33189             };
33190             var fileMap = _mainFileFetcher.fileMap();
33191
33192             for (var scopeId in localeDirs) {
33193               var key = "locales_index_".concat(scopeId);
33194               fileMap[key] = localeDirs[scopeId] + '/index.min.json';
33195               filesToFetch.push(key);
33196             }
33197
33198             return _loadPromise = Promise.all(filesToFetch.map(function (key) {
33199               return _mainFileFetcher.get(key);
33200             })).then(function (results) {
33201               _dataLanguages = results[0];
33202               _dataLocales = results[1];
33203               var indexes = results.slice(2);
33204
33205               var requestedLocales = (_preferredLocaleCodes || []). // List of locales preferred by the browser in priority order.
33206               concat(utilDetect().browserLocales) // fallback to English since it's the only guaranteed complete language
33207               .concat(['en']);
33208
33209               _localeCodes = localesToUseFrom(requestedLocales); // Run iD in the highest-priority locale; the rest are fallbacks
33210
33211               _localeCode = _localeCodes[0];
33212               var loadStringsPromises = [];
33213               indexes.forEach(function (index, i) {
33214                 // Will always return the index for `en` if nothing else
33215                 var fullCoverageIndex = _localeCodes.findIndex(function (locale) {
33216                   return index[locale] && index[locale].pct === 1;
33217                 }); // We only need to load locales up until we find one with full coverage
33218
33219
33220                 _localeCodes.slice(0, fullCoverageIndex + 1).forEach(function (code) {
33221                   var scopeId = Object.keys(localeDirs)[i];
33222                   var directory = Object.values(localeDirs)[i];
33223                   if (index[code]) loadStringsPromises.push(localizer.loadLocale(code, scopeId, directory));
33224                 });
33225               });
33226               return Promise.all(loadStringsPromises);
33227             }).then(function () {
33228               updateForCurrentLocale();
33229             })["catch"](function (err) {
33230               return console.error(err);
33231             }); // eslint-disable-line
33232           }; // Returns the locales from `requestedLocales` supported by iD that we should use
33233
33234
33235           function localesToUseFrom(requestedLocales) {
33236             var supportedLocales = _dataLocales;
33237             var toUse = [];
33238
33239             for (var i in requestedLocales) {
33240               var locale = requestedLocales[i];
33241               if (supportedLocales[locale]) toUse.push(locale);
33242
33243               if (locale.includes('-')) {
33244                 // Full locale ('es-ES'), add fallback to the base ('es')
33245                 var langPart = locale.split('-')[0];
33246                 if (supportedLocales[langPart]) toUse.push(langPart);
33247               }
33248             } // remove duplicates
33249
33250
33251             return utilArrayUniq(toUse);
33252           }
33253
33254           function updateForCurrentLocale() {
33255             if (!_localeCode) return;
33256             _languageCode = _localeCode.split('-')[0];
33257             var currentData = _dataLocales[_localeCode] || _dataLocales[_languageCode];
33258             var hash = utilStringQs(window.location.hash);
33259
33260             if (hash.rtl === 'true') {
33261               _textDirection = 'rtl';
33262             } else if (hash.rtl === 'false') {
33263               _textDirection = 'ltr';
33264             } else {
33265               _textDirection = currentData && currentData.rtl ? 'rtl' : 'ltr';
33266             }
33267
33268             var locale = _localeCode;
33269             if (locale.toLowerCase() === 'en-us') locale = 'en';
33270             _languageNames = _localeStrings.general[locale].languageNames;
33271             _scriptNames = _localeStrings.general[locale].scriptNames;
33272             _usesMetric = _localeCode.slice(-3).toLowerCase() !== '-us';
33273           }
33274           /* Locales */
33275           // Returns a Promise to load the strings for the requested locale
33276
33277
33278           localizer.loadLocale = function (locale, scopeId, directory) {
33279             // US English is the default
33280             if (locale.toLowerCase() === 'en-us') locale = 'en';
33281
33282             if (_localeStrings[scopeId] && _localeStrings[scopeId][locale]) {
33283               // already loaded
33284               return Promise.resolve(locale);
33285             }
33286
33287             var fileMap = _mainFileFetcher.fileMap();
33288             var key = "locale_".concat(scopeId, "_").concat(locale);
33289             fileMap[key] = "".concat(directory, "/").concat(locale, ".min.json");
33290             return _mainFileFetcher.get(key).then(function (d) {
33291               if (!_localeStrings[scopeId]) _localeStrings[scopeId] = {};
33292               _localeStrings[scopeId][locale] = d[locale];
33293               return locale;
33294             });
33295           };
33296
33297           localizer.pluralRule = function (number) {
33298             return pluralRule(number, _localeCode);
33299           }; // Returns the plural rule for the given `number` with the given `localeCode`.
33300           // One of: `zero`, `one`, `two`, `few`, `many`, `other`
33301
33302
33303           function pluralRule(number, localeCode) {
33304             // modern browsers have this functionality built-in
33305             var rules = 'Intl' in window && Intl.PluralRules && new Intl.PluralRules(localeCode);
33306
33307             if (rules) {
33308               return rules.select(number);
33309             } // fallback to basic one/other, as in English
33310
33311
33312             if (number === 1) return 'one';
33313             return 'other';
33314           }
33315           /**
33316           * Try to find that string in `locale` or the current `_localeCode` matching
33317           * the given `stringId`. If no string can be found in the requested locale,
33318           * we'll recurse down all the `_localeCodes` until one is found.
33319           *
33320           * @param  {string}   stringId      string identifier
33321           * @param  {object?}  replacements  token replacements and default string
33322           * @param  {string?}  locale        locale to use (defaults to currentLocale)
33323           * @return {string?}  localized string
33324           */
33325
33326
33327           localizer.tInfo = function (origStringId, replacements, locale) {
33328             var stringId = origStringId.trim();
33329             var scopeId = 'general';
33330
33331             if (stringId[0] === '_') {
33332               var split = stringId.split('.');
33333               scopeId = split[0].slice(1);
33334               stringId = split.slice(1).join('.');
33335             }
33336
33337             locale = locale || _localeCode;
33338             var path = stringId.split('.').map(function (s) {
33339               return s.replace(/<TX_DOT>/g, '.');
33340             }).reverse();
33341             var stringsKey = locale; // US English is the default
33342
33343             if (stringsKey.toLowerCase() === 'en-us') stringsKey = 'en';
33344             var result = _localeStrings && _localeStrings[scopeId] && _localeStrings[scopeId][stringsKey];
33345
33346             while (result !== undefined && path.length) {
33347               result = result[path.pop()];
33348             }
33349
33350             if (result !== undefined) {
33351               if (replacements) {
33352                 if (_typeof(result) === 'object' && Object.keys(result).length) {
33353                   // If plural forms are provided, dig one level deeper based on the
33354                   // first numeric token replacement provided.
33355                   var number = Object.values(replacements).find(function (value) {
33356                     return typeof value === 'number';
33357                   });
33358
33359                   if (number !== undefined) {
33360                     var rule = pluralRule(number, locale);
33361
33362                     if (result[rule]) {
33363                       result = result[rule];
33364                     } else {
33365                       // We're pretty sure this should be a plural but no string
33366                       // could be found for the given rule. Just pick the first
33367                       // string and hope it makes sense.
33368                       result = Object.values(result)[0];
33369                     }
33370                   }
33371                 }
33372
33373                 if (typeof result === 'string') {
33374                   for (var key in replacements) {
33375                     var value = replacements[key];
33376
33377                     if (typeof value === 'number') {
33378                       if (value.toLocaleString) {
33379                         // format numbers for the locale
33380                         value = value.toLocaleString(locale, {
33381                           style: 'decimal',
33382                           useGrouping: true,
33383                           minimumFractionDigits: 0
33384                         });
33385                       } else {
33386                         value = value.toString();
33387                       }
33388                     }
33389
33390                     var token = "{".concat(key, "}");
33391                     var regex = new RegExp(token, 'g');
33392                     result = result.replace(regex, value);
33393                   }
33394                 }
33395               }
33396
33397               if (typeof result === 'string') {
33398                 // found a localized string!
33399                 return {
33400                   text: result,
33401                   locale: locale
33402                 };
33403               }
33404             } // no localized string found...
33405             // attempt to fallback to a lower-priority language
33406
33407
33408             var index = _localeCodes.indexOf(locale);
33409
33410             if (index >= 0 && index < _localeCodes.length - 1) {
33411               // eventually this will be 'en' or another locale with 100% coverage
33412               var fallback = _localeCodes[index + 1];
33413               return localizer.tInfo(origStringId, replacements, fallback);
33414             }
33415
33416             if (replacements && 'default' in replacements) {
33417               // Fallback to a default value if one is specified in `replacements`
33418               return {
33419                 text: replacements["default"],
33420                 locale: null
33421               };
33422             }
33423
33424             var missing = "Missing ".concat(locale, " translation: ").concat(origStringId);
33425             if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
33426
33427             return {
33428               text: missing,
33429               locale: 'en'
33430             };
33431           };
33432
33433           localizer.hasTextForStringId = function (stringId) {
33434             return !!localizer.tInfo(stringId, {
33435               "default": 'nothing found'
33436             }).locale;
33437           }; // Returns only the localized text, discarding the locale info
33438
33439
33440           localizer.t = function (stringId, replacements, locale) {
33441             return localizer.tInfo(stringId, replacements, locale).text;
33442           }; // Returns the localized text wrapped in an HTML element encoding the locale info
33443
33444
33445           localizer.t.html = function (stringId, replacements, locale) {
33446             var info = localizer.tInfo(stringId, replacements, locale); // text may be empty or undefined if `replacements.default` is
33447
33448             return info.text ? localizer.htmlForLocalizedText(info.text, info.locale) : '';
33449           };
33450
33451           localizer.htmlForLocalizedText = function (text, localeCode) {
33452             return "<span class=\"localized-text\" lang=\"".concat(localeCode || 'unknown', "\">").concat(text, "</span>");
33453           };
33454
33455           localizer.languageName = function (code, options) {
33456             if (_languageNames[code]) {
33457               // name in locale language
33458               // e.g. "German"
33459               return _languageNames[code];
33460             } // sometimes we only want the local name
33461
33462
33463             if (options && options.localOnly) return null;
33464             var langInfo = _dataLanguages[code];
33465
33466             if (langInfo) {
33467               if (langInfo.nativeName) {
33468                 // name in native language
33469                 // e.g. "Deutsch (de)"
33470                 return localizer.t('translate.language_and_code', {
33471                   language: langInfo.nativeName,
33472                   code: code
33473                 });
33474               } else if (langInfo.base && langInfo.script) {
33475                 var base = langInfo.base; // the code of the language this is based on
33476
33477                 if (_languageNames[base]) {
33478                   // base language name in locale language
33479                   var scriptCode = langInfo.script;
33480                   var script = _scriptNames[scriptCode] || scriptCode; // e.g. "Serbian (Cyrillic)"
33481
33482                   return localizer.t('translate.language_and_code', {
33483                     language: _languageNames[base],
33484                     code: script
33485                   });
33486                 } else if (_dataLanguages[base] && _dataLanguages[base].nativeName) {
33487                   // e.g. "српски (sr-Cyrl)"
33488                   return localizer.t('translate.language_and_code', {
33489                     language: _dataLanguages[base].nativeName,
33490                     code: code
33491                   });
33492                 }
33493               }
33494             }
33495
33496             return code; // if not found, use the code
33497           };
33498
33499           return localizer;
33500         }
33501
33502         // `presetCollection` is a wrapper around an `Array` of presets `collection`,
33503         // and decorated with some extra methods for searching and matching geometry
33504         //
33505
33506         function presetCollection(collection) {
33507           var MAXRESULTS = 50;
33508           var _this = {};
33509           var _memo = {};
33510           _this.collection = collection;
33511
33512           _this.item = function (id) {
33513             if (_memo[id]) return _memo[id];
33514
33515             var found = _this.collection.find(function (d) {
33516               return d.id === id;
33517             });
33518
33519             if (found) _memo[id] = found;
33520             return found;
33521           };
33522
33523           _this.index = function (id) {
33524             return _this.collection.findIndex(function (d) {
33525               return d.id === id;
33526             });
33527           };
33528
33529           _this.matchGeometry = function (geometry) {
33530             return presetCollection(_this.collection.filter(function (d) {
33531               return d.matchGeometry(geometry);
33532             }));
33533           };
33534
33535           _this.matchAllGeometry = function (geometries) {
33536             return presetCollection(_this.collection.filter(function (d) {
33537               return d && d.matchAllGeometry(geometries);
33538             }));
33539           };
33540
33541           _this.matchAnyGeometry = function (geometries) {
33542             return presetCollection(_this.collection.filter(function (d) {
33543               return geometries.some(function (geom) {
33544                 return d.matchGeometry(geom);
33545               });
33546             }));
33547           };
33548
33549           _this.fallback = function (geometry) {
33550             var id = geometry;
33551             if (id === 'vertex') id = 'point';
33552             return _this.item(id);
33553           };
33554
33555           _this.search = function (value, geometry, loc) {
33556             if (!value) return _this; // don't remove diacritical characters since we're assuming the user is being intentional
33557
33558             value = value.toLowerCase().trim(); // match at name beginning or just after a space (e.g. "office" -> match "Law Office")
33559
33560             function leading(a) {
33561               var index = a.indexOf(value);
33562               return index === 0 || a[index - 1] === ' ';
33563             } // match at name beginning only
33564
33565
33566             function leadingStrict(a) {
33567               var index = a.indexOf(value);
33568               return index === 0;
33569             }
33570
33571             function sortPresets(nameProp) {
33572               return function sortNames(a, b) {
33573                 var aCompare = a[nameProp]();
33574                 var bCompare = b[nameProp](); // priority if search string matches preset name exactly - #4325
33575
33576                 if (value === aCompare) return -1;
33577                 if (value === bCompare) return 1; // priority for higher matchScore
33578
33579                 var i = b.originalScore - a.originalScore;
33580                 if (i !== 0) return i; // priority if search string appears earlier in preset name
33581
33582                 i = aCompare.indexOf(value) - bCompare.indexOf(value);
33583                 if (i !== 0) return i; // priority for shorter preset names
33584
33585                 return aCompare.length - bCompare.length;
33586               };
33587             }
33588
33589             var pool = _this.collection;
33590
33591             if (Array.isArray(loc)) {
33592               var validLocations = _mainLocations.locationsAt(loc);
33593               pool = pool.filter(function (a) {
33594                 return !a.locationSetID || validLocations[a.locationSetID];
33595               });
33596             }
33597
33598             var searchable = pool.filter(function (a) {
33599               return a.searchable !== false && a.suggestion !== true;
33600             });
33601             var suggestions = pool.filter(function (a) {
33602               return a.suggestion === true;
33603             }); // matches value to preset.name
33604
33605             var leadingNames = searchable.filter(function (a) {
33606               return leading(a.searchName());
33607             }).sort(sortPresets('searchName')); // matches value to preset suggestion name
33608
33609             var leadingSuggestions = suggestions.filter(function (a) {
33610               return leadingStrict(a.searchName());
33611             }).sort(sortPresets('searchName'));
33612             var leadingNamesStripped = searchable.filter(function (a) {
33613               return leading(a.searchNameStripped());
33614             }).sort(sortPresets('searchNameStripped'));
33615             var leadingSuggestionsStripped = suggestions.filter(function (a) {
33616               return leadingStrict(a.searchNameStripped());
33617             }).sort(sortPresets('searchNameStripped')); // matches value to preset.terms values
33618
33619             var leadingTerms = searchable.filter(function (a) {
33620               return (a.terms() || []).some(leading);
33621             });
33622             var leadingSuggestionTerms = suggestions.filter(function (a) {
33623               return (a.terms() || []).some(leading);
33624             }); // matches value to preset.tags values
33625
33626             var leadingTagValues = searchable.filter(function (a) {
33627               return Object.values(a.tags || {}).filter(function (val) {
33628                 return val !== '*';
33629               }).some(leading);
33630             }); // finds close matches to value in preset.name
33631
33632             var similarName = searchable.map(function (a) {
33633               return {
33634                 preset: a,
33635                 dist: utilEditDistance(value, a.searchName())
33636               };
33637             }).filter(function (a) {
33638               return a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 3;
33639             }).sort(function (a, b) {
33640               return a.dist - b.dist;
33641             }).map(function (a) {
33642               return a.preset;
33643             }); // finds close matches to value to preset suggestion name
33644
33645             var similarSuggestions = suggestions.map(function (a) {
33646               return {
33647                 preset: a,
33648                 dist: utilEditDistance(value, a.searchName())
33649               };
33650             }).filter(function (a) {
33651               return a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 1;
33652             }).sort(function (a, b) {
33653               return a.dist - b.dist;
33654             }).map(function (a) {
33655               return a.preset;
33656             }); // finds close matches to value in preset.terms
33657
33658             var similarTerms = searchable.filter(function (a) {
33659               return (a.terms() || []).some(function (b) {
33660                 return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
33661               });
33662             });
33663             var results = leadingNames.concat(leadingSuggestions, leadingNamesStripped, leadingSuggestionsStripped, leadingTerms, leadingSuggestionTerms, leadingTagValues, similarName, similarSuggestions, similarTerms).slice(0, MAXRESULTS - 1);
33664
33665             if (geometry) {
33666               if (typeof geometry === 'string') {
33667                 results.push(_this.fallback(geometry));
33668               } else {
33669                 geometry.forEach(function (geom) {
33670                   return results.push(_this.fallback(geom));
33671                 });
33672               }
33673             }
33674
33675             return presetCollection(utilArrayUniq(results));
33676           };
33677
33678           return _this;
33679         }
33680
33681         // `presetCategory` builds a `presetCollection` of member presets,
33682         // decorated with some extra methods for searching and matching geometry
33683         //
33684
33685         function presetCategory(categoryID, category, allPresets) {
33686           var _this = Object.assign({}, category); // shallow copy
33687
33688
33689           var _searchName; // cache
33690
33691
33692           var _searchNameStripped; // cache
33693
33694
33695           _this.id = categoryID;
33696           _this.members = presetCollection((category.members || []).map(function (presetID) {
33697             return allPresets[presetID];
33698           }).filter(Boolean));
33699           _this.geometry = _this.members.collection.reduce(function (acc, preset) {
33700             for (var i in preset.geometry) {
33701               var geometry = preset.geometry[i];
33702
33703               if (acc.indexOf(geometry) === -1) {
33704                 acc.push(geometry);
33705               }
33706             }
33707
33708             return acc;
33709           }, []);
33710
33711           _this.matchGeometry = function (geom) {
33712             return _this.geometry.indexOf(geom) >= 0;
33713           };
33714
33715           _this.matchAllGeometry = function (geometries) {
33716             return _this.members.collection.some(function (preset) {
33717               return preset.matchAllGeometry(geometries);
33718             });
33719           };
33720
33721           _this.matchScore = function () {
33722             return -1;
33723           };
33724
33725           _this.name = function () {
33726             return _t("_tagging.presets.categories.".concat(categoryID, ".name"), {
33727               'default': categoryID
33728             });
33729           };
33730
33731           _this.nameLabel = function () {
33732             return _t.html("_tagging.presets.categories.".concat(categoryID, ".name"), {
33733               'default': categoryID
33734             });
33735           };
33736
33737           _this.terms = function () {
33738             return [];
33739           };
33740
33741           _this.searchName = function () {
33742             if (!_searchName) {
33743               _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
33744             }
33745
33746             return _searchName;
33747           };
33748
33749           _this.searchNameStripped = function () {
33750             if (!_searchNameStripped) {
33751               _searchNameStripped = _this.searchName(); // split combined diacritical characters into their parts
33752
33753               if (_searchNameStripped.normalize) _searchNameStripped = _searchNameStripped.normalize('NFD'); // remove diacritics
33754
33755               _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, '');
33756             }
33757
33758             return _searchNameStripped;
33759           };
33760
33761           return _this;
33762         }
33763
33764         // `presetField` decorates a given `field` Object
33765         // with some extra methods for searching and matching geometry
33766         //
33767
33768         function presetField(fieldID, field) {
33769           var _this = Object.assign({}, field); // shallow copy
33770
33771
33772           _this.id = fieldID; // for use in classes, element ids, css selectors
33773
33774           _this.safeid = utilSafeClassName(fieldID);
33775
33776           _this.matchGeometry = function (geom) {
33777             return !_this.geometry || _this.geometry.indexOf(geom) !== -1;
33778           };
33779
33780           _this.matchAllGeometry = function (geometries) {
33781             return !_this.geometry || geometries.every(function (geom) {
33782               return _this.geometry.indexOf(geom) !== -1;
33783             });
33784           };
33785
33786           _this.t = function (scope, options) {
33787             return _t("_tagging.presets.fields.".concat(fieldID, ".").concat(scope), options);
33788           };
33789
33790           _this.t.html = function (scope, options) {
33791             return _t.html("_tagging.presets.fields.".concat(fieldID, ".").concat(scope), options);
33792           };
33793
33794           _this.hasTextForStringId = function (scope) {
33795             return _mainLocalizer.hasTextForStringId("_tagging.presets.fields.".concat(fieldID, ".").concat(scope));
33796           };
33797
33798           _this.title = function () {
33799             return _this.overrideLabel || _this.t('label', {
33800               'default': fieldID
33801             });
33802           };
33803
33804           _this.label = function () {
33805             return _this.overrideLabel || _this.t.html('label', {
33806               'default': fieldID
33807             });
33808           };
33809
33810           var _placeholder = _this.placeholder;
33811
33812           _this.placeholder = function () {
33813             return _this.t('placeholder', {
33814               'default': _placeholder
33815             });
33816           };
33817
33818           _this.originalTerms = (_this.terms || []).join();
33819
33820           _this.terms = function () {
33821             return _this.t('terms', {
33822               'default': _this.originalTerms
33823             }).toLowerCase().trim().split(/\s*,+\s*/);
33824           };
33825
33826           _this.increment = _this.type === 'number' ? _this.increment || 1 : undefined;
33827           return _this;
33828         }
33829
33830         // `Array.prototype.lastIndexOf` method
33831         // https://tc39.es/ecma262/#sec-array.prototype.lastindexof
33832         // eslint-disable-next-line es/no-array-prototype-lastindexof -- required for testing
33833         _export({ target: 'Array', proto: true, forced: arrayLastIndexOf !== [].lastIndexOf }, {
33834           lastIndexOf: arrayLastIndexOf
33835         });
33836
33837         // `presetPreset` decorates a given `preset` Object
33838         // with some extra methods for searching and matching geometry
33839         //
33840
33841         function presetPreset(presetID, preset, addable, allFields, allPresets) {
33842           allFields = allFields || {};
33843           allPresets = allPresets || {};
33844
33845           var _this = Object.assign({}, preset); // shallow copy
33846
33847
33848           var _addable = addable || false;
33849
33850           var _resolvedFields; // cache
33851
33852
33853           var _resolvedMoreFields; // cache
33854
33855
33856           var _searchName; // cache
33857
33858
33859           var _searchNameStripped; // cache
33860
33861
33862           _this.id = presetID;
33863           _this.safeid = utilSafeClassName(presetID); // for use in css classes, selectors, element ids
33864
33865           _this.originalTerms = (_this.terms || []).join();
33866           _this.originalName = _this.name || '';
33867           _this.originalScore = _this.matchScore || 1;
33868           _this.originalReference = _this.reference || {};
33869           _this.originalFields = _this.fields || [];
33870           _this.originalMoreFields = _this.moreFields || [];
33871
33872           _this.fields = function () {
33873             return _resolvedFields || (_resolvedFields = resolve('fields'));
33874           };
33875
33876           _this.moreFields = function () {
33877             return _resolvedMoreFields || (_resolvedMoreFields = resolve('moreFields'));
33878           };
33879
33880           _this.resetFields = function () {
33881             return _resolvedFields = _resolvedMoreFields = null;
33882           };
33883
33884           _this.tags = _this.tags || {};
33885           _this.addTags = _this.addTags || _this.tags;
33886           _this.removeTags = _this.removeTags || _this.addTags;
33887           _this.geometry = _this.geometry || [];
33888
33889           _this.matchGeometry = function (geom) {
33890             return _this.geometry.indexOf(geom) >= 0;
33891           };
33892
33893           _this.matchAllGeometry = function (geoms) {
33894             return geoms.every(_this.matchGeometry);
33895           };
33896
33897           _this.matchScore = function (entityTags) {
33898             var tags = _this.tags;
33899             var seen = {};
33900             var score = 0; // match on tags
33901
33902             for (var k in tags) {
33903               seen[k] = true;
33904
33905               if (entityTags[k] === tags[k]) {
33906                 score += _this.originalScore;
33907               } else if (tags[k] === '*' && k in entityTags) {
33908                 score += _this.originalScore / 2;
33909               } else {
33910                 return -1;
33911               }
33912             } // boost score for additional matches in addTags - #6802
33913
33914
33915             var addTags = _this.addTags;
33916
33917             for (var _k in addTags) {
33918               if (!seen[_k] && entityTags[_k] === addTags[_k]) {
33919                 score += _this.originalScore;
33920               }
33921             }
33922
33923             return score;
33924           };
33925
33926           _this.t = function (scope, options) {
33927             var textID = "_tagging.presets.presets.".concat(presetID, ".").concat(scope);
33928             return _t(textID, options);
33929           };
33930
33931           _this.t.html = function (scope, options) {
33932             var textID = "_tagging.presets.presets.".concat(presetID, ".").concat(scope);
33933             return _t.html(textID, options);
33934           };
33935
33936           _this.name = function () {
33937             return _this.t('name', {
33938               'default': _this.originalName
33939             });
33940           };
33941
33942           _this.nameLabel = function () {
33943             return _this.t.html('name', {
33944               'default': _this.originalName
33945             });
33946           };
33947
33948           _this.subtitle = function () {
33949             if (_this.suggestion) {
33950               var path = presetID.split('/');
33951               path.pop(); // remove brand name
33952
33953               return _t('_tagging.presets.presets.' + path.join('/') + '.name');
33954             }
33955
33956             return null;
33957           };
33958
33959           _this.subtitleLabel = function () {
33960             if (_this.suggestion) {
33961               var path = presetID.split('/');
33962               path.pop(); // remove brand name
33963
33964               return _t.html('_tagging.presets.presets.' + path.join('/') + '.name');
33965             }
33966
33967             return null;
33968           };
33969
33970           _this.terms = function () {
33971             return _this.t('terms', {
33972               'default': _this.originalTerms
33973             }).toLowerCase().trim().split(/\s*,+\s*/);
33974           };
33975
33976           _this.searchName = function () {
33977             if (!_searchName) {
33978               _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
33979             }
33980
33981             return _searchName;
33982           };
33983
33984           _this.searchNameStripped = function () {
33985             if (!_searchNameStripped) {
33986               _searchNameStripped = _this.searchName(); // split combined diacritical characters into their parts
33987
33988               if (_searchNameStripped.normalize) _searchNameStripped = _searchNameStripped.normalize('NFD'); // remove diacritics
33989
33990               _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, '');
33991             }
33992
33993             return _searchNameStripped;
33994           };
33995
33996           _this.isFallback = function () {
33997             var tagCount = Object.keys(_this.tags).length;
33998             return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty('area');
33999           };
34000
34001           _this.addable = function (val) {
34002             if (!arguments.length) return _addable;
34003             _addable = val;
34004             return _this;
34005           };
34006
34007           _this.reference = function () {
34008             // Lookup documentation on Wikidata...
34009             var qid = _this.tags.wikidata || _this.tags['flag:wikidata'] || _this.tags['brand:wikidata'] || _this.tags['network:wikidata'] || _this.tags['operator:wikidata'];
34010
34011             if (qid) {
34012               return {
34013                 qid: qid
34014               };
34015             } // Lookup documentation on OSM Wikibase...
34016
34017
34018             var key = _this.originalReference.key || Object.keys(utilObjectOmit(_this.tags, 'name'))[0];
34019             var value = _this.originalReference.value || _this.tags[key];
34020
34021             if (value === '*') {
34022               return {
34023                 key: key
34024               };
34025             } else {
34026               return {
34027                 key: key,
34028                 value: value
34029               };
34030             }
34031           };
34032
34033           _this.unsetTags = function (tags, geometry, ignoringKeys, skipFieldDefaults) {
34034             // allow manually keeping some tags
34035             var removeTags = ignoringKeys ? utilObjectOmit(_this.removeTags, ignoringKeys) : _this.removeTags;
34036             tags = utilObjectOmit(tags, Object.keys(removeTags));
34037
34038             if (geometry && !skipFieldDefaults) {
34039               _this.fields().forEach(function (field) {
34040                 if (field.matchGeometry(geometry) && field.key && field["default"] === tags[field.key]) {
34041                   delete tags[field.key];
34042                 }
34043               });
34044             }
34045
34046             delete tags.area;
34047             return tags;
34048           };
34049
34050           _this.setTags = function (tags, geometry, skipFieldDefaults) {
34051             var addTags = _this.addTags;
34052             tags = Object.assign({}, tags); // shallow copy
34053
34054             for (var k in addTags) {
34055               if (addTags[k] === '*') {
34056                 // if this tag is ancillary, don't override an existing value since any value is okay
34057                 if (_this.tags[k] || !tags[k] || tags[k] === 'no') {
34058                   tags[k] = 'yes';
34059                 }
34060               } else {
34061                 tags[k] = addTags[k];
34062               }
34063             } // Add area=yes if necessary.
34064             // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
34065             // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
34066             // 2. chosen preset doesn't have a key in osmAreaKeys (`railway=station`)
34067
34068
34069             if (!addTags.hasOwnProperty('area')) {
34070               delete tags.area;
34071
34072               if (geometry === 'area') {
34073                 var needsAreaTag = true;
34074
34075                 if (_this.geometry.indexOf('line') === -1) {
34076                   for (var _k2 in addTags) {
34077                     if (_k2 in osmAreaKeys) {
34078                       needsAreaTag = false;
34079                       break;
34080                     }
34081                   }
34082                 }
34083
34084                 if (needsAreaTag) {
34085                   tags.area = 'yes';
34086                 }
34087               }
34088             }
34089
34090             if (geometry && !skipFieldDefaults) {
34091               _this.fields().forEach(function (field) {
34092                 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field["default"]) {
34093                   tags[field.key] = field["default"];
34094                 }
34095               });
34096             }
34097
34098             return tags;
34099           }; // For a preset without fields, use the fields of the parent preset.
34100           // Replace {preset} placeholders with the fields of the specified presets.
34101
34102
34103           function resolve(which) {
34104             var fieldIDs = which === 'fields' ? _this.originalFields : _this.originalMoreFields;
34105             var resolved = [];
34106             fieldIDs.forEach(function (fieldID) {
34107               var match = fieldID.match(/\{(.*)\}/);
34108
34109               if (match !== null) {
34110                 // a presetID wrapped in braces {}
34111                 resolved = resolved.concat(inheritFields(match[1], which));
34112               } else if (allFields[fieldID]) {
34113                 // a normal fieldID
34114                 resolved.push(allFields[fieldID]);
34115               } else {
34116                 console.log("Cannot resolve \"".concat(fieldID, "\" found in ").concat(_this.id, ".").concat(which)); // eslint-disable-line no-console
34117               }
34118             }); // no fields resolved, so use the parent's if possible
34119
34120             if (!resolved.length) {
34121               var endIndex = _this.id.lastIndexOf('/');
34122
34123               var parentID = endIndex && _this.id.substring(0, endIndex);
34124
34125               if (parentID) {
34126                 resolved = inheritFields(parentID, which);
34127               }
34128             }
34129
34130             return utilArrayUniq(resolved); // returns an array of fields to inherit from the given presetID, if found
34131
34132             function inheritFields(presetID, which) {
34133               var parent = allPresets[presetID];
34134               if (!parent) return [];
34135
34136               if (which === 'fields') {
34137                 return parent.fields().filter(shouldInherit);
34138               } else if (which === 'moreFields') {
34139                 return parent.moreFields();
34140               } else {
34141                 return [];
34142               }
34143             } // Skip `fields` for the keys which define the preset.
34144             // These are usually `typeCombo` fields like `shop=*`
34145
34146
34147             function shouldInherit(f) {
34148               if (f.key && _this.tags[f.key] !== undefined && // inherit anyway if multiple values are allowed or just a checkbox
34149               f.type !== 'multiCombo' && f.type !== 'semiCombo' && f.type !== 'manyCombo' && f.type !== 'check') return false;
34150               return true;
34151             }
34152           }
34153
34154           return _this;
34155         }
34156
34157         var _mainPresetIndex = presetIndex(); // singleton
34158         // `presetIndex` wraps a `presetCollection`
34159         // with methods for loading new data and returning defaults
34160         //
34161
34162         function presetIndex() {
34163           var dispatch = dispatch$8('favoritePreset', 'recentsChange');
34164           var MAXRECENTS = 30; // seed the preset lists with geometry fallbacks
34165
34166           var POINT = presetPreset('point', {
34167             name: 'Point',
34168             tags: {},
34169             geometry: ['point', 'vertex'],
34170             matchScore: 0.1
34171           });
34172           var LINE = presetPreset('line', {
34173             name: 'Line',
34174             tags: {},
34175             geometry: ['line'],
34176             matchScore: 0.1
34177           });
34178           var AREA = presetPreset('area', {
34179             name: 'Area',
34180             tags: {
34181               area: 'yes'
34182             },
34183             geometry: ['area'],
34184             matchScore: 0.1
34185           });
34186           var RELATION = presetPreset('relation', {
34187             name: 'Relation',
34188             tags: {},
34189             geometry: ['relation'],
34190             matchScore: 0.1
34191           });
34192
34193           var _this = presetCollection([POINT, LINE, AREA, RELATION]);
34194
34195           var _presets = {
34196             point: POINT,
34197             line: LINE,
34198             area: AREA,
34199             relation: RELATION
34200           };
34201           var _defaults = {
34202             point: presetCollection([POINT]),
34203             vertex: presetCollection([POINT]),
34204             line: presetCollection([LINE]),
34205             area: presetCollection([AREA]),
34206             relation: presetCollection([RELATION])
34207           };
34208           var _fields = {};
34209           var _categories = {};
34210           var _universal = [];
34211           var _addablePresetIDs = null; // Set of preset IDs that the user can add
34212
34213           var _recents;
34214
34215           var _favorites; // Index of presets by (geometry, tag key).
34216
34217
34218           var _geometryIndex = {
34219             point: {},
34220             vertex: {},
34221             line: {},
34222             area: {},
34223             relation: {}
34224           };
34225
34226           var _loadPromise;
34227
34228           _this.ensureLoaded = function () {
34229             if (_loadPromise) return _loadPromise;
34230             return _loadPromise = Promise.all([_mainFileFetcher.get('preset_categories'), _mainFileFetcher.get('preset_defaults'), _mainFileFetcher.get('preset_presets'), _mainFileFetcher.get('preset_fields')]).then(function (vals) {
34231               _this.merge({
34232                 categories: vals[0],
34233                 defaults: vals[1],
34234                 presets: vals[2],
34235                 fields: vals[3]
34236               });
34237
34238               osmSetAreaKeys(_this.areaKeys());
34239               osmSetPointTags(_this.pointTags());
34240               osmSetVertexTags(_this.vertexTags());
34241             });
34242           }; // `merge` accepts an object containing new preset data (all properties optional):
34243           // {
34244           //   fields: {},
34245           //   presets: {},
34246           //   categories: {},
34247           //   defaults: {},
34248           //   featureCollection: {}
34249           //}
34250
34251
34252           _this.merge = function (d) {
34253             var newLocationSets = []; // Merge Fields
34254
34255             if (d.fields) {
34256               Object.keys(d.fields).forEach(function (fieldID) {
34257                 var f = d.fields[fieldID];
34258
34259                 if (f) {
34260                   // add or replace
34261                   f = presetField(fieldID, f);
34262                   if (f.locationSet) newLocationSets.push(f);
34263                   _fields[fieldID] = f;
34264                 } else {
34265                   // remove
34266                   delete _fields[fieldID];
34267                 }
34268               });
34269             } // Merge Presets
34270
34271
34272             if (d.presets) {
34273               Object.keys(d.presets).forEach(function (presetID) {
34274                 var p = d.presets[presetID];
34275
34276                 if (p) {
34277                   // add or replace
34278                   var isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
34279
34280                   p = presetPreset(presetID, p, isAddable, _fields, _presets);
34281                   if (p.locationSet) newLocationSets.push(p);
34282                   _presets[presetID] = p;
34283                 } else {
34284                   // remove (but not if it's a fallback)
34285                   var existing = _presets[presetID];
34286
34287                   if (existing && !existing.isFallback()) {
34288                     delete _presets[presetID];
34289                   }
34290                 }
34291               });
34292             } // Merge Categories
34293
34294
34295             if (d.categories) {
34296               Object.keys(d.categories).forEach(function (categoryID) {
34297                 var c = d.categories[categoryID];
34298
34299                 if (c) {
34300                   // add or replace
34301                   c = presetCategory(categoryID, c, _presets);
34302                   if (c.locationSet) newLocationSets.push(c);
34303                   _categories[categoryID] = c;
34304                 } else {
34305                   // remove
34306                   delete _categories[categoryID];
34307                 }
34308               });
34309             } // Rebuild _this.collection after changing presets and categories
34310
34311
34312             _this.collection = Object.values(_presets).concat(Object.values(_categories)); // Merge Defaults
34313
34314             if (d.defaults) {
34315               Object.keys(d.defaults).forEach(function (geometry) {
34316                 var def = d.defaults[geometry];
34317
34318                 if (Array.isArray(def)) {
34319                   // add or replace
34320                   _defaults[geometry] = presetCollection(def.map(function (id) {
34321                     return _presets[id] || _categories[id];
34322                   }).filter(Boolean));
34323                 } else {
34324                   // remove
34325                   delete _defaults[geometry];
34326                 }
34327               });
34328             } // Rebuild universal fields array
34329
34330
34331             _universal = Object.values(_fields).filter(function (field) {
34332               return field.universal;
34333             }); // Reset all the preset fields - they'll need to be resolved again
34334
34335             Object.values(_presets).forEach(function (preset) {
34336               return preset.resetFields();
34337             }); // Rebuild geometry index
34338
34339             _geometryIndex = {
34340               point: {},
34341               vertex: {},
34342               line: {},
34343               area: {},
34344               relation: {}
34345             };
34346
34347             _this.collection.forEach(function (preset) {
34348               (preset.geometry || []).forEach(function (geometry) {
34349                 var g = _geometryIndex[geometry];
34350
34351                 for (var key in preset.tags) {
34352                   (g[key] = g[key] || []).push(preset);
34353                 }
34354               });
34355             }); // Merge Custom Features
34356
34357
34358             if (d.featureCollection && Array.isArray(d.featureCollection.features)) {
34359               _mainLocations.mergeCustomGeoJSON(d.featureCollection);
34360             } // Resolve all locationSet features.
34361
34362
34363             if (newLocationSets.length) {
34364               _mainLocations.mergeLocationSets(newLocationSets);
34365             }
34366
34367             return _this;
34368           };
34369
34370           _this.match = function (entity, resolver) {
34371             return resolver["transient"](entity, 'presetMatch', function () {
34372               var geometry = entity.geometry(resolver); // Treat entities on addr:interpolation lines as points, not vertices - #3241
34373
34374               if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
34375                 geometry = 'point';
34376               }
34377
34378               var entityExtent = entity.extent(resolver);
34379               return _this.matchTags(entity.tags, geometry, entityExtent.center());
34380             });
34381           };
34382
34383           _this.matchTags = function (tags, geometry, loc) {
34384             var geometryMatches = _geometryIndex[geometry];
34385             var address;
34386             var best = -1;
34387             var match;
34388             var validLocations;
34389
34390             if (Array.isArray(loc)) {
34391               validLocations = _mainLocations.locationsAt(loc);
34392             }
34393
34394             for (var k in tags) {
34395               // If any part of an address is present, allow fallback to "Address" preset - #4353
34396               if (/^addr:/.test(k) && geometryMatches['addr:*']) {
34397                 address = geometryMatches['addr:*'][0];
34398               }
34399
34400               var keyMatches = geometryMatches[k];
34401               if (!keyMatches) continue;
34402
34403               for (var i = 0; i < keyMatches.length; i++) {
34404                 var candidate = keyMatches[i]; // discard candidate preset if location is not valid at `loc`
34405
34406                 if (validLocations && candidate.locationSetID) {
34407                   if (!validLocations[candidate.locationSetID]) continue;
34408                 }
34409
34410                 var score = candidate.matchScore(tags);
34411
34412                 if (score > best) {
34413                   best = score;
34414                   match = candidate;
34415                 }
34416               }
34417             }
34418
34419             if (address && (!match || match.isFallback())) {
34420               match = address;
34421             }
34422
34423             return match || _this.fallback(geometry);
34424           };
34425
34426           _this.allowsVertex = function (entity, resolver) {
34427             if (entity.type !== 'node') return false;
34428             if (Object.keys(entity.tags).length === 0) return true;
34429             return resolver["transient"](entity, 'vertexMatch', function () {
34430               // address lines allow vertices to act as standalone points
34431               if (entity.isOnAddressLine(resolver)) return true;
34432               var geometries = osmNodeGeometriesForTags(entity.tags);
34433               if (geometries.vertex) return true;
34434               if (geometries.point) return false; // allow vertices for unspecified points
34435
34436               return true;
34437             });
34438           }; // Because of the open nature of tagging, iD will never have a complete
34439           // list of tags used in OSM, so we want it to have logic like "assume
34440           // that a closed way with an amenity tag is an area, unless the amenity
34441           // is one of these specific types". This function computes a structure
34442           // that allows testing of such conditions, based on the presets designated
34443           // as as supporting (or not supporting) the area geometry.
34444           //
34445           // The returned object L is a keeplist/discardlist of tags. A closed way
34446           // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
34447           // (see `Way#isArea()`). In other words, the keys of L form the keeplist,
34448           // and the subkeys form the discardlist.
34449
34450
34451           _this.areaKeys = function () {
34452             // The ignore list is for keys that imply lines. (We always add `area=yes` for exceptions)
34453             var ignore = ['barrier', 'highway', 'footway', 'railway', 'junction', 'type'];
34454             var areaKeys = {}; // ignore name-suggestion-index and deprecated presets
34455
34456             var presets = _this.collection.filter(function (p) {
34457               return !p.suggestion && !p.replacement;
34458             }); // keeplist
34459
34460
34461             presets.forEach(function (p) {
34462               var keys = p.tags && Object.keys(p.tags);
34463               var key = keys && keys.length && keys[0]; // pick the first tag
34464
34465               if (!key) return;
34466               if (ignore.indexOf(key) !== -1) return;
34467
34468               if (p.geometry.indexOf('area') !== -1) {
34469                 // probably an area..
34470                 areaKeys[key] = areaKeys[key] || {};
34471               }
34472             }); // discardlist
34473
34474             presets.forEach(function (p) {
34475               var key;
34476
34477               for (key in p.addTags) {
34478                 // examine all addTags to get a better sense of what can be tagged on lines - #6800
34479                 var value = p.addTags[key];
34480
34481                 if (key in areaKeys && // probably an area...
34482                 p.geometry.indexOf('line') !== -1 && // but sometimes a line
34483                 value !== '*') {
34484                   areaKeys[key][value] = true;
34485                 }
34486               }
34487             });
34488             return areaKeys;
34489           };
34490
34491           _this.pointTags = function () {
34492             return _this.collection.reduce(function (pointTags, d) {
34493               // ignore name-suggestion-index, deprecated, and generic presets
34494               if (d.suggestion || d.replacement || d.searchable === false) return pointTags; // only care about the primary tag
34495
34496               var keys = d.tags && Object.keys(d.tags);
34497               var key = keys && keys.length && keys[0]; // pick the first tag
34498
34499               if (!key) return pointTags; // if this can be a point
34500
34501               if (d.geometry.indexOf('point') !== -1) {
34502                 pointTags[key] = pointTags[key] || {};
34503                 pointTags[key][d.tags[key]] = true;
34504               }
34505
34506               return pointTags;
34507             }, {});
34508           };
34509
34510           _this.vertexTags = function () {
34511             return _this.collection.reduce(function (vertexTags, d) {
34512               // ignore name-suggestion-index, deprecated, and generic presets
34513               if (d.suggestion || d.replacement || d.searchable === false) return vertexTags; // only care about the primary tag
34514
34515               var keys = d.tags && Object.keys(d.tags);
34516               var key = keys && keys.length && keys[0]; // pick the first tag
34517
34518               if (!key) return vertexTags; // if this can be a vertex
34519
34520               if (d.geometry.indexOf('vertex') !== -1) {
34521                 vertexTags[key] = vertexTags[key] || {};
34522                 vertexTags[key][d.tags[key]] = true;
34523               }
34524
34525               return vertexTags;
34526             }, {});
34527           };
34528
34529           _this.field = function (id) {
34530             return _fields[id];
34531           };
34532
34533           _this.universal = function () {
34534             return _universal;
34535           };
34536
34537           _this.defaults = function (geometry, n, startWithRecents, loc) {
34538             var recents = [];
34539
34540             if (startWithRecents) {
34541               recents = _this.recent().matchGeometry(geometry).collection.slice(0, 4);
34542             }
34543
34544             var defaults;
34545
34546             if (_addablePresetIDs) {
34547               defaults = Array.from(_addablePresetIDs).map(function (id) {
34548                 var preset = _this.item(id);
34549
34550                 if (preset && preset.matchGeometry(geometry)) return preset;
34551                 return null;
34552               }).filter(Boolean);
34553             } else {
34554               defaults = _defaults[geometry].collection.concat(_this.fallback(geometry));
34555             }
34556
34557             var result = presetCollection(utilArrayUniq(recents.concat(defaults)).slice(0, n - 1));
34558
34559             if (Array.isArray(loc)) {
34560               var validLocations = _mainLocations.locationsAt(loc);
34561               result.collection = result.collection.filter(function (a) {
34562                 return !a.locationSetID || validLocations[a.locationSetID];
34563               });
34564             }
34565
34566             return result;
34567           }; // pass a Set of addable preset ids
34568
34569
34570           _this.addablePresetIDs = function (val) {
34571             if (!arguments.length) return _addablePresetIDs; // accept and convert arrays
34572
34573             if (Array.isArray(val)) val = new Set(val);
34574             _addablePresetIDs = val;
34575
34576             if (_addablePresetIDs) {
34577               // reset all presets
34578               _this.collection.forEach(function (p) {
34579                 // categories aren't addable
34580                 if (p.addable) p.addable(_addablePresetIDs.has(p.id));
34581               });
34582             } else {
34583               _this.collection.forEach(function (p) {
34584                 if (p.addable) p.addable(true);
34585               });
34586             }
34587
34588             return _this;
34589           };
34590
34591           _this.recent = function () {
34592             return presetCollection(utilArrayUniq(_this.getRecents().map(function (d) {
34593               return d.preset;
34594             })));
34595           };
34596
34597           function RibbonItem(preset, source) {
34598             var item = {};
34599             item.preset = preset;
34600             item.source = source;
34601
34602             item.isFavorite = function () {
34603               return item.source === 'favorite';
34604             };
34605
34606             item.isRecent = function () {
34607               return item.source === 'recent';
34608             };
34609
34610             item.matches = function (preset) {
34611               return item.preset.id === preset.id;
34612             };
34613
34614             item.minified = function () {
34615               return {
34616                 pID: item.preset.id
34617               };
34618             };
34619
34620             return item;
34621           }
34622
34623           function ribbonItemForMinified(d, source) {
34624             if (d && d.pID) {
34625               var preset = _this.item(d.pID);
34626
34627               if (!preset) return null;
34628               return RibbonItem(preset, source);
34629             }
34630
34631             return null;
34632           }
34633
34634           _this.getGenericRibbonItems = function () {
34635             return ['point', 'line', 'area'].map(function (id) {
34636               return RibbonItem(_this.item(id), 'generic');
34637             });
34638           };
34639
34640           _this.getAddable = function () {
34641             if (!_addablePresetIDs) return [];
34642             return _addablePresetIDs.map(function (id) {
34643               var preset = _this.item(id);
34644
34645               if (preset) return RibbonItem(preset, 'addable');
34646               return null;
34647             }).filter(Boolean);
34648           };
34649
34650           function setRecents(items) {
34651             _recents = items;
34652             var minifiedItems = items.map(function (d) {
34653               return d.minified();
34654             });
34655             corePreferences('preset_recents', JSON.stringify(minifiedItems));
34656             dispatch.call('recentsChange');
34657           }
34658
34659           _this.getRecents = function () {
34660             if (!_recents) {
34661               // fetch from local storage
34662               _recents = (JSON.parse(corePreferences('preset_recents')) || []).reduce(function (acc, d) {
34663                 var item = ribbonItemForMinified(d, 'recent');
34664                 if (item && item.preset.addable()) acc.push(item);
34665                 return acc;
34666               }, []);
34667             }
34668
34669             return _recents;
34670           };
34671
34672           _this.addRecent = function (preset, besidePreset, after) {
34673             var recents = _this.getRecents();
34674
34675             var beforeItem = _this.recentMatching(besidePreset);
34676
34677             var toIndex = recents.indexOf(beforeItem);
34678             if (after) toIndex += 1;
34679             var newItem = RibbonItem(preset, 'recent');
34680             recents.splice(toIndex, 0, newItem);
34681             setRecents(recents);
34682           };
34683
34684           _this.removeRecent = function (preset) {
34685             var item = _this.recentMatching(preset);
34686
34687             if (item) {
34688               var items = _this.getRecents();
34689
34690               items.splice(items.indexOf(item), 1);
34691               setRecents(items);
34692             }
34693           };
34694
34695           _this.recentMatching = function (preset) {
34696             var items = _this.getRecents();
34697
34698             for (var i in items) {
34699               if (items[i].matches(preset)) {
34700                 return items[i];
34701               }
34702             }
34703
34704             return null;
34705           };
34706
34707           _this.moveItem = function (items, fromIndex, toIndex) {
34708             if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= items.length || toIndex >= items.length) return null;
34709             items.splice(toIndex, 0, items.splice(fromIndex, 1)[0]);
34710             return items;
34711           };
34712
34713           _this.moveRecent = function (item, beforeItem) {
34714             var recents = _this.getRecents();
34715
34716             var fromIndex = recents.indexOf(item);
34717             var toIndex = recents.indexOf(beforeItem);
34718
34719             var items = _this.moveItem(recents, fromIndex, toIndex);
34720
34721             if (items) setRecents(items);
34722           };
34723
34724           _this.setMostRecent = function (preset) {
34725             if (preset.searchable === false) return;
34726
34727             var items = _this.getRecents();
34728
34729             var item = _this.recentMatching(preset);
34730
34731             if (item) {
34732               items.splice(items.indexOf(item), 1);
34733             } else {
34734               item = RibbonItem(preset, 'recent');
34735             } // remove the last recent (first in, first out)
34736
34737
34738             while (items.length >= MAXRECENTS) {
34739               items.pop();
34740             } // prepend array
34741
34742
34743             items.unshift(item);
34744             setRecents(items);
34745           };
34746
34747           function setFavorites(items) {
34748             _favorites = items;
34749             var minifiedItems = items.map(function (d) {
34750               return d.minified();
34751             });
34752             corePreferences('preset_favorites', JSON.stringify(minifiedItems)); // call update
34753
34754             dispatch.call('favoritePreset');
34755           }
34756
34757           _this.addFavorite = function (preset, besidePreset, after) {
34758             var favorites = _this.getFavorites();
34759
34760             var beforeItem = _this.favoriteMatching(besidePreset);
34761
34762             var toIndex = favorites.indexOf(beforeItem);
34763             if (after) toIndex += 1;
34764             var newItem = RibbonItem(preset, 'favorite');
34765             favorites.splice(toIndex, 0, newItem);
34766             setFavorites(favorites);
34767           };
34768
34769           _this.toggleFavorite = function (preset) {
34770             var favs = _this.getFavorites();
34771
34772             var favorite = _this.favoriteMatching(preset);
34773
34774             if (favorite) {
34775               favs.splice(favs.indexOf(favorite), 1);
34776             } else {
34777               // only allow 10 favorites
34778               if (favs.length === 10) {
34779                 // remove the last favorite (last in, first out)
34780                 favs.pop();
34781               } // append array
34782
34783
34784               favs.push(RibbonItem(preset, 'favorite'));
34785             }
34786
34787             setFavorites(favs);
34788           };
34789
34790           _this.removeFavorite = function (preset) {
34791             var item = _this.favoriteMatching(preset);
34792
34793             if (item) {
34794               var items = _this.getFavorites();
34795
34796               items.splice(items.indexOf(item), 1);
34797               setFavorites(items);
34798             }
34799           };
34800
34801           _this.getFavorites = function () {
34802             if (!_favorites) {
34803               // fetch from local storage
34804               var rawFavorites = JSON.parse(corePreferences('preset_favorites'));
34805
34806               if (!rawFavorites) {
34807                 rawFavorites = [];
34808                 corePreferences('preset_favorites', JSON.stringify(rawFavorites));
34809               }
34810
34811               _favorites = rawFavorites.reduce(function (output, d) {
34812                 var item = ribbonItemForMinified(d, 'favorite');
34813                 if (item && item.preset.addable()) output.push(item);
34814                 return output;
34815               }, []);
34816             }
34817
34818             return _favorites;
34819           };
34820
34821           _this.favoriteMatching = function (preset) {
34822             var favs = _this.getFavorites();
34823
34824             for (var index in favs) {
34825               if (favs[index].matches(preset)) {
34826                 return favs[index];
34827               }
34828             }
34829
34830             return null;
34831           };
34832
34833           return utilRebind(_this, dispatch, 'on');
34834         }
34835
34836         function utilTagText(entity) {
34837           var obj = entity && entity.tags || {};
34838           return Object.keys(obj).map(function (k) {
34839             return k + '=' + obj[k];
34840           }).join(', ');
34841         }
34842         function utilTotalExtent(array, graph) {
34843           var extent = geoExtent();
34844           var val, entity;
34845
34846           for (var i = 0; i < array.length; i++) {
34847             val = array[i];
34848             entity = typeof val === 'string' ? graph.hasEntity(val) : val;
34849
34850             if (entity) {
34851               extent._extend(entity.extent(graph));
34852             }
34853           }
34854
34855           return extent;
34856         }
34857         function utilTagDiff(oldTags, newTags) {
34858           var tagDiff = [];
34859           var keys = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
34860           keys.forEach(function (k) {
34861             var oldVal = oldTags[k];
34862             var newVal = newTags[k];
34863
34864             if ((oldVal || oldVal === '') && (newVal === undefined || newVal !== oldVal)) {
34865               tagDiff.push({
34866                 type: '-',
34867                 key: k,
34868                 oldVal: oldVal,
34869                 newVal: newVal,
34870                 display: '- ' + k + '=' + oldVal
34871               });
34872             }
34873
34874             if ((newVal || newVal === '') && (oldVal === undefined || newVal !== oldVal)) {
34875               tagDiff.push({
34876                 type: '+',
34877                 key: k,
34878                 oldVal: oldVal,
34879                 newVal: newVal,
34880                 display: '+ ' + k + '=' + newVal
34881               });
34882             }
34883           });
34884           return tagDiff;
34885         }
34886         function utilEntitySelector(ids) {
34887           return ids.length ? '.' + ids.join(',.') : 'nothing';
34888         } // returns an selector to select entity ids for:
34889         //  - entityIDs passed in
34890         //  - shallow descendant entityIDs for any of those entities that are relations
34891
34892         function utilEntityOrMemberSelector(ids, graph) {
34893           var seen = new Set(ids);
34894           ids.forEach(collectShallowDescendants);
34895           return utilEntitySelector(Array.from(seen));
34896
34897           function collectShallowDescendants(id) {
34898             var entity = graph.hasEntity(id);
34899             if (!entity || entity.type !== 'relation') return;
34900             entity.members.map(function (member) {
34901               return member.id;
34902             }).forEach(function (id) {
34903               seen.add(id);
34904             });
34905           }
34906         } // returns an selector to select entity ids for:
34907         //  - entityIDs passed in
34908         //  - deep descendant entityIDs for any of those entities that are relations
34909
34910         function utilEntityOrDeepMemberSelector(ids, graph) {
34911           return utilEntitySelector(utilEntityAndDeepMemberIDs(ids, graph));
34912         } // returns an selector to select entity ids for:
34913         //  - entityIDs passed in
34914         //  - deep descendant entityIDs for any of those entities that are relations
34915
34916         function utilEntityAndDeepMemberIDs(ids, graph) {
34917           var seen = new Set();
34918           ids.forEach(collectDeepDescendants);
34919           return Array.from(seen);
34920
34921           function collectDeepDescendants(id) {
34922             if (seen.has(id)) return;
34923             seen.add(id);
34924             var entity = graph.hasEntity(id);
34925             if (!entity || entity.type !== 'relation') return;
34926             entity.members.map(function (member) {
34927               return member.id;
34928             }).forEach(collectDeepDescendants); // recurse
34929           }
34930         } // returns an selector to select entity ids for:
34931         //  - deep descendant entityIDs for any of those entities that are relations
34932
34933         function utilDeepMemberSelector(ids, graph, skipMultipolgonMembers) {
34934           var idsSet = new Set(ids);
34935           var seen = new Set();
34936           var returners = new Set();
34937           ids.forEach(collectDeepDescendants);
34938           return utilEntitySelector(Array.from(returners));
34939
34940           function collectDeepDescendants(id) {
34941             if (seen.has(id)) return;
34942             seen.add(id);
34943
34944             if (!idsSet.has(id)) {
34945               returners.add(id);
34946             }
34947
34948             var entity = graph.hasEntity(id);
34949             if (!entity || entity.type !== 'relation') return;
34950             if (skipMultipolgonMembers && entity.isMultipolygon()) return;
34951             entity.members.map(function (member) {
34952               return member.id;
34953             }).forEach(collectDeepDescendants); // recurse
34954           }
34955         } // Adds or removes highlight styling for the specified entities
34956
34957         function utilHighlightEntities(ids, highlighted, context) {
34958           context.surface().selectAll(utilEntityOrDeepMemberSelector(ids, context.graph())).classed('highlighted', highlighted);
34959         } // returns an Array that is the union of:
34960         //  - nodes for any nodeIDs passed in
34961         //  - child nodes of any wayIDs passed in
34962         //  - descendant member and child nodes of relationIDs passed in
34963
34964         function utilGetAllNodes(ids, graph) {
34965           var seen = new Set();
34966           var nodes = new Set();
34967           ids.forEach(collectNodes);
34968           return Array.from(nodes);
34969
34970           function collectNodes(id) {
34971             if (seen.has(id)) return;
34972             seen.add(id);
34973             var entity = graph.hasEntity(id);
34974             if (!entity) return;
34975
34976             if (entity.type === 'node') {
34977               nodes.add(entity);
34978             } else if (entity.type === 'way') {
34979               entity.nodes.forEach(collectNodes);
34980             } else {
34981               entity.members.map(function (member) {
34982                 return member.id;
34983               }).forEach(collectNodes); // recurse
34984             }
34985           }
34986         }
34987         function utilDisplayName(entity) {
34988           var localizedNameKey = 'name:' + _mainLocalizer.languageCode().toLowerCase();
34989           var name = entity.tags[localizedNameKey] || entity.tags.name || '';
34990           if (name) return name;
34991           var tags = {
34992             direction: entity.tags.direction,
34993             from: entity.tags.from,
34994             network: entity.tags.cycle_network || entity.tags.network,
34995             ref: entity.tags.ref,
34996             to: entity.tags.to,
34997             via: entity.tags.via
34998           };
34999           var keyComponents = [];
35000
35001           if (tags.network) {
35002             keyComponents.push('network');
35003           }
35004
35005           if (tags.ref) {
35006             keyComponents.push('ref');
35007           } // Routes may need more disambiguation based on direction or destination
35008
35009
35010           if (entity.tags.route) {
35011             if (tags.direction) {
35012               keyComponents.push('direction');
35013             } else if (tags.from && tags.to) {
35014               keyComponents.push('from');
35015               keyComponents.push('to');
35016
35017               if (tags.via) {
35018                 keyComponents.push('via');
35019               }
35020             }
35021           }
35022
35023           if (keyComponents.length) {
35024             name = _t('inspector.display_name.' + keyComponents.join('_'), tags);
35025           }
35026
35027           return name;
35028         }
35029         function utilDisplayNameForPath(entity) {
35030           var name = utilDisplayName(entity);
35031           var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
35032
35033           if (!isFirefox && name && rtlRegex.test(name)) {
35034             name = fixRTLTextForSvg(name);
35035           }
35036
35037           return name;
35038         }
35039         function utilDisplayType(id) {
35040           return {
35041             n: _t('inspector.node'),
35042             w: _t('inspector.way'),
35043             r: _t('inspector.relation')
35044           }[id.charAt(0)];
35045         } // `utilDisplayLabel`
35046         // Returns a string suitable for display
35047         // By default returns something like name/ref, fallback to preset type, fallback to OSM type
35048         //   "Main Street" or "Tertiary Road"
35049         // If `verbose=true`, include both preset name and feature name.
35050         //   "Tertiary Road Main Street"
35051         //
35052
35053         function utilDisplayLabel(entity, graphOrGeometry, verbose) {
35054           var result;
35055           var displayName = utilDisplayName(entity);
35056           var preset = typeof graphOrGeometry === 'string' ? _mainPresetIndex.matchTags(entity.tags, graphOrGeometry) : _mainPresetIndex.match(entity, graphOrGeometry);
35057           var presetName = preset && (preset.suggestion ? preset.subtitle() : preset.name());
35058
35059           if (verbose) {
35060             result = [presetName, displayName].filter(Boolean).join(' ');
35061           } else {
35062             result = displayName || presetName;
35063           } // Fallback to the OSM type (node/way/relation)
35064
35065
35066           return result || utilDisplayType(entity.id);
35067         }
35068         function utilEntityRoot(entityType) {
35069           return {
35070             node: 'n',
35071             way: 'w',
35072             relation: 'r'
35073           }[entityType];
35074         } // Returns a single object containing the tags of all the given entities.
35075         // Example:
35076         // {
35077         //   highway: 'service',
35078         //   service: 'parking_aisle'
35079         // }
35080         //           +
35081         // {
35082         //   highway: 'service',
35083         //   service: 'driveway',
35084         //   width: '3'
35085         // }
35086         //           =
35087         // {
35088         //   highway: 'service',
35089         //   service: [ 'driveway', 'parking_aisle' ],
35090         //   width: [ '3', undefined ]
35091         // }
35092
35093         function utilCombinedTags(entityIDs, graph) {
35094           var tags = {};
35095           var tagCounts = {};
35096           var allKeys = new Set();
35097           var entities = entityIDs.map(function (entityID) {
35098             return graph.hasEntity(entityID);
35099           }).filter(Boolean); // gather the aggregate keys
35100
35101           entities.forEach(function (entity) {
35102             var keys = Object.keys(entity.tags).filter(Boolean);
35103             keys.forEach(function (key) {
35104               allKeys.add(key);
35105             });
35106           });
35107           entities.forEach(function (entity) {
35108             allKeys.forEach(function (key) {
35109               var value = entity.tags[key]; // purposely allow `undefined`
35110
35111               if (!tags.hasOwnProperty(key)) {
35112                 // first value, set as raw
35113                 tags[key] = value;
35114               } else {
35115                 if (!Array.isArray(tags[key])) {
35116                   if (tags[key] !== value) {
35117                     // first alternate value, replace single value with array
35118                     tags[key] = [tags[key], value];
35119                   }
35120                 } else {
35121                   // type is array
35122                   if (tags[key].indexOf(value) === -1) {
35123                     // subsequent alternate value, add to array
35124                     tags[key].push(value);
35125                   }
35126                 }
35127               }
35128
35129               var tagHash = key + '=' + value;
35130               if (!tagCounts[tagHash]) tagCounts[tagHash] = 0;
35131               tagCounts[tagHash] += 1;
35132             });
35133           });
35134
35135           for (var key in tags) {
35136             if (!Array.isArray(tags[key])) continue; // sort values by frequency then alphabetically
35137
35138             tags[key] = tags[key].sort(function (val1, val2) {
35139               var key = key; // capture
35140
35141               var count2 = tagCounts[key + '=' + val2];
35142               var count1 = tagCounts[key + '=' + val1];
35143
35144               if (count2 !== count1) {
35145                 return count2 - count1;
35146               }
35147
35148               if (val2 && val1) {
35149                 return val1.localeCompare(val2);
35150               }
35151
35152               return val1 ? 1 : -1;
35153             });
35154           }
35155
35156           return tags;
35157         }
35158         function utilStringQs(str) {
35159           var i = 0; // advance past any leading '?' or '#' characters
35160
35161           while (i < str.length && (str[i] === '?' || str[i] === '#')) {
35162             i++;
35163           }
35164
35165           str = str.slice(i);
35166           return str.split('&').reduce(function (obj, pair) {
35167             var parts = pair.split('=');
35168
35169             if (parts.length === 2) {
35170               obj[parts[0]] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
35171             }
35172
35173             return obj;
35174           }, {});
35175         }
35176         function utilQsString(obj, noencode) {
35177           // encode everything except special characters used in certain hash parameters:
35178           // "/" in map states, ":", ",", {" and "}" in background
35179           function softEncode(s) {
35180             return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
35181           }
35182
35183           return Object.keys(obj).sort().map(function (key) {
35184             return encodeURIComponent(key) + '=' + (noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
35185           }).join('&');
35186         }
35187         function utilPrefixDOMProperty(property) {
35188           var prefixes = ['webkit', 'ms', 'moz', 'o'];
35189           var i = -1;
35190           var n = prefixes.length;
35191           var s = document.body;
35192           if (property in s) return property;
35193           property = property.substr(0, 1).toUpperCase() + property.substr(1);
35194
35195           while (++i < n) {
35196             if (prefixes[i] + property in s) {
35197               return prefixes[i] + property;
35198             }
35199           }
35200
35201           return false;
35202         }
35203         function utilPrefixCSSProperty(property) {
35204           var prefixes = ['webkit', 'ms', 'Moz', 'O'];
35205           var i = -1;
35206           var n = prefixes.length;
35207           var s = document.body.style;
35208
35209           if (property.toLowerCase() in s) {
35210             return property.toLowerCase();
35211           }
35212
35213           while (++i < n) {
35214             if (prefixes[i] + property in s) {
35215               return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
35216             }
35217           }
35218
35219           return false;
35220         }
35221         var transformProperty;
35222         function utilSetTransform(el, x, y, scale) {
35223           var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform');
35224           var translate = utilDetect().opera ? 'translate(' + x + 'px,' + y + 'px)' : 'translate3d(' + x + 'px,' + y + 'px,0)';
35225           return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
35226         } // Calculates Levenshtein distance between two strings
35227         // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
35228         // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
35229
35230         function utilEditDistance(a, b) {
35231           a = remove$6(a.toLowerCase());
35232           b = remove$6(b.toLowerCase());
35233           if (a.length === 0) return b.length;
35234           if (b.length === 0) return a.length;
35235           var matrix = [];
35236           var i, j;
35237
35238           for (i = 0; i <= b.length; i++) {
35239             matrix[i] = [i];
35240           }
35241
35242           for (j = 0; j <= a.length; j++) {
35243             matrix[0][j] = j;
35244           }
35245
35246           for (i = 1; i <= b.length; i++) {
35247             for (j = 1; j <= a.length; j++) {
35248               if (b.charAt(i - 1) === a.charAt(j - 1)) {
35249                 matrix[i][j] = matrix[i - 1][j - 1];
35250               } else {
35251                 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
35252                 Math.min(matrix[i][j - 1] + 1, // insertion
35253                 matrix[i - 1][j] + 1)); // deletion
35254               }
35255             }
35256           }
35257
35258           return matrix[b.length][a.length];
35259         } // a d3.mouse-alike which
35260         // 1. Only works on HTML elements, not SVG
35261         // 2. Does not cause style recalculation
35262
35263         function utilFastMouse(container) {
35264           var rect = container.getBoundingClientRect();
35265           var rectLeft = rect.left;
35266           var rectTop = rect.top;
35267           var clientLeft = +container.clientLeft;
35268           var clientTop = +container.clientTop;
35269           return function (e) {
35270             return [e.clientX - rectLeft - clientLeft, e.clientY - rectTop - clientTop];
35271           };
35272         }
35273         function utilAsyncMap(inputs, func, callback) {
35274           var remaining = inputs.length;
35275           var results = [];
35276           var errors = [];
35277           inputs.forEach(function (d, i) {
35278             func(d, function done(err, data) {
35279               errors[i] = err;
35280               results[i] = data;
35281               remaining--;
35282               if (!remaining) callback(errors, results);
35283             });
35284           });
35285         } // wraps an index to an interval [0..length-1]
35286
35287         function utilWrap(index, length) {
35288           if (index < 0) {
35289             index += Math.ceil(-index / length) * length;
35290           }
35291
35292           return index % length;
35293         }
35294         /**
35295          * a replacement for functor
35296          *
35297          * @param {*} value any value
35298          * @returns {Function} a function that returns that value or the value if it's a function
35299          */
35300
35301         function utilFunctor(value) {
35302           if (typeof value === 'function') return value;
35303           return function () {
35304             return value;
35305           };
35306         }
35307         function utilNoAuto(selection) {
35308           var isText = selection.size() && selection.node().tagName.toLowerCase() === 'textarea';
35309           return selection // assign 'new-password' even for non-password fields to prevent browsers (Chrome) ignoring 'off'
35310           .attr('autocomplete', 'new-password').attr('autocorrect', 'off').attr('autocapitalize', 'off').attr('spellcheck', isText ? 'true' : 'false');
35311         } // https://stackoverflow.com/questions/194846/is-there-any-kind-of-hash-code-function-in-javascript
35312         // https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
35313
35314         function utilHashcode(str) {
35315           var hash = 0;
35316
35317           if (str.length === 0) {
35318             return hash;
35319           }
35320
35321           for (var i = 0; i < str.length; i++) {
35322             var _char = str.charCodeAt(i);
35323
35324             hash = (hash << 5) - hash + _char;
35325             hash = hash & hash; // Convert to 32bit integer
35326           }
35327
35328           return hash;
35329         } // Returns version of `str` with all runs of special characters replaced by `_`;
35330         // suitable for HTML ids, classes, selectors, etc.
35331
35332         function utilSafeClassName(str) {
35333           return str.toLowerCase().replace(/[^a-z0-9]+/g, '_');
35334         } // Returns string based on `val` that is highly unlikely to collide with an id
35335         // used previously or that's present elsewhere in the document. Useful for preventing
35336         // browser-provided autofills or when embedding iD on pages with unknown elements.
35337
35338         function utilUniqueDomId(val) {
35339           return 'ideditor-' + utilSafeClassName(val.toString()) + '-' + new Date().getTime().toString();
35340         } // Returns the length of `str` in unicode characters. This can be less than
35341         // `String.length()` since a single unicode character can be composed of multiple
35342         // JavaScript UTF-16 code units.
35343
35344         function utilUnicodeCharsCount(str) {
35345           // Native ES2015 implementations of `Array.from` split strings into unicode characters
35346           return Array.from(str).length;
35347         } // Returns a new string representing `str` cut from its start to `limit` length
35348         // in unicode characters. Note that this runs the risk of splitting graphemes.
35349
35350         function utilUnicodeCharsTruncated(str, limit) {
35351           return Array.from(str).slice(0, limit).join('');
35352         } // Variation of d3.json (https://github.com/d3/d3-fetch/blob/master/src/json.js)
35353
35354         function utilFetchJson(resourse, init) {
35355           return fetch(resourse, init).then(function (response) {
35356             // fetch in PhantomJS tests may return ok=false and status=0 even if it's okay
35357             if (!response.ok && response.status !== 0 || !response.json) throw new Error(response.status + ' ' + response.statusText);
35358             if (response.status === 204 || response.status === 205) return;
35359             return response.json();
35360           });
35361         }
35362
35363         function osmEntity(attrs) {
35364           // For prototypal inheritance.
35365           if (this instanceof osmEntity) return; // Create the appropriate subtype.
35366
35367           if (attrs && attrs.type) {
35368             return osmEntity[attrs.type].apply(this, arguments);
35369           } else if (attrs && attrs.id) {
35370             return osmEntity[osmEntity.id.type(attrs.id)].apply(this, arguments);
35371           } // Initialize a generic Entity (used only in tests).
35372
35373
35374           return new osmEntity().initialize(arguments);
35375         }
35376
35377         osmEntity.id = function (type) {
35378           return osmEntity.id.fromOSM(type, osmEntity.id.next[type]--);
35379         };
35380
35381         osmEntity.id.next = {
35382           changeset: -1,
35383           node: -1,
35384           way: -1,
35385           relation: -1
35386         };
35387
35388         osmEntity.id.fromOSM = function (type, id) {
35389           return type[0] + id;
35390         };
35391
35392         osmEntity.id.toOSM = function (id) {
35393           return id.slice(1);
35394         };
35395
35396         osmEntity.id.type = function (id) {
35397           return {
35398             'c': 'changeset',
35399             'n': 'node',
35400             'w': 'way',
35401             'r': 'relation'
35402           }[id[0]];
35403         }; // A function suitable for use as the second argument to d3.selection#data().
35404
35405
35406         osmEntity.key = function (entity) {
35407           return entity.id + 'v' + (entity.v || 0);
35408         };
35409
35410         var _deprecatedTagValuesByKey;
35411
35412         osmEntity.deprecatedTagValuesByKey = function (dataDeprecated) {
35413           if (!_deprecatedTagValuesByKey) {
35414             _deprecatedTagValuesByKey = {};
35415             dataDeprecated.forEach(function (d) {
35416               var oldKeys = Object.keys(d.old);
35417
35418               if (oldKeys.length === 1) {
35419                 var oldKey = oldKeys[0];
35420                 var oldValue = d.old[oldKey];
35421
35422                 if (oldValue !== '*') {
35423                   if (!_deprecatedTagValuesByKey[oldKey]) {
35424                     _deprecatedTagValuesByKey[oldKey] = [oldValue];
35425                   } else {
35426                     _deprecatedTagValuesByKey[oldKey].push(oldValue);
35427                   }
35428                 }
35429               }
35430             });
35431           }
35432
35433           return _deprecatedTagValuesByKey;
35434         };
35435
35436         osmEntity.prototype = {
35437           tags: {},
35438           initialize: function initialize(sources) {
35439             for (var i = 0; i < sources.length; ++i) {
35440               var source = sources[i];
35441
35442               for (var prop in source) {
35443                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
35444                   if (source[prop] === undefined) {
35445                     delete this[prop];
35446                   } else {
35447                     this[prop] = source[prop];
35448                   }
35449                 }
35450               }
35451             }
35452
35453             if (!this.id && this.type) {
35454               this.id = osmEntity.id(this.type);
35455             }
35456
35457             if (!this.hasOwnProperty('visible')) {
35458               this.visible = true;
35459             }
35460
35461             if (debug) {
35462               Object.freeze(this);
35463               Object.freeze(this.tags);
35464               if (this.loc) Object.freeze(this.loc);
35465               if (this.nodes) Object.freeze(this.nodes);
35466               if (this.members) Object.freeze(this.members);
35467             }
35468
35469             return this;
35470           },
35471           copy: function copy(resolver, copies) {
35472             if (copies[this.id]) return copies[this.id];
35473             var copy = osmEntity(this, {
35474               id: undefined,
35475               user: undefined,
35476               version: undefined
35477             });
35478             copies[this.id] = copy;
35479             return copy;
35480           },
35481           osmId: function osmId() {
35482             return osmEntity.id.toOSM(this.id);
35483           },
35484           isNew: function isNew() {
35485             return this.osmId() < 0;
35486           },
35487           update: function update(attrs) {
35488             return osmEntity(this, attrs, {
35489               v: 1 + (this.v || 0)
35490             });
35491           },
35492           mergeTags: function mergeTags(tags) {
35493             var merged = Object.assign({}, this.tags); // shallow copy
35494
35495             var changed = false;
35496
35497             for (var k in tags) {
35498               var t1 = merged[k];
35499               var t2 = tags[k];
35500
35501               if (!t1) {
35502                 changed = true;
35503                 merged[k] = t2;
35504               } else if (t1 !== t2) {
35505                 changed = true;
35506                 merged[k] = utilUnicodeCharsTruncated(utilArrayUnion(t1.split(/;\s*/), t2.split(/;\s*/)).join(';'), 255 // avoid exceeding character limit; see also services/osm.js -> maxCharsForTagValue()
35507                 );
35508               }
35509             }
35510
35511             return changed ? this.update({
35512               tags: merged
35513             }) : this;
35514           },
35515           intersects: function intersects(extent, resolver) {
35516             return this.extent(resolver).intersects(extent);
35517           },
35518           hasNonGeometryTags: function hasNonGeometryTags() {
35519             return Object.keys(this.tags).some(function (k) {
35520               return k !== 'area';
35521             });
35522           },
35523           hasParentRelations: function hasParentRelations(resolver) {
35524             return resolver.parentRelations(this).length > 0;
35525           },
35526           hasInterestingTags: function hasInterestingTags() {
35527             return Object.keys(this.tags).some(osmIsInterestingTag);
35528           },
35529           isHighwayIntersection: function isHighwayIntersection() {
35530             return false;
35531           },
35532           isDegenerate: function isDegenerate() {
35533             return true;
35534           },
35535           deprecatedTags: function deprecatedTags(dataDeprecated) {
35536             var tags = this.tags; // if there are no tags, none can be deprecated
35537
35538             if (Object.keys(tags).length === 0) return [];
35539             var deprecated = [];
35540             dataDeprecated.forEach(function (d) {
35541               var oldKeys = Object.keys(d.old);
35542
35543               if (d.replace) {
35544                 var hasExistingValues = Object.keys(d.replace).some(function (replaceKey) {
35545                   if (!tags[replaceKey] || d.old[replaceKey]) return false;
35546                   var replaceValue = d.replace[replaceKey];
35547                   if (replaceValue === '*') return false;
35548                   if (replaceValue === tags[replaceKey]) return false;
35549                   return true;
35550                 }); // don't flag deprecated tags if the upgrade path would overwrite existing data - #7843
35551
35552                 if (hasExistingValues) return;
35553               }
35554
35555               var matchesDeprecatedTags = oldKeys.every(function (oldKey) {
35556                 if (!tags[oldKey]) return false;
35557                 if (d.old[oldKey] === '*') return true;
35558                 if (d.old[oldKey] === tags[oldKey]) return true;
35559                 var vals = tags[oldKey].split(';').filter(Boolean);
35560
35561                 if (vals.length === 0) {
35562                   return false;
35563                 } else if (vals.length > 1) {
35564                   return vals.indexOf(d.old[oldKey]) !== -1;
35565                 } else {
35566                   if (tags[oldKey] === d.old[oldKey]) {
35567                     if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
35568                       var replaceKeys = Object.keys(d.replace);
35569                       return !replaceKeys.every(function (replaceKey) {
35570                         return tags[replaceKey] === d.replace[replaceKey];
35571                       });
35572                     } else {
35573                       return true;
35574                     }
35575                   }
35576                 }
35577
35578                 return false;
35579               });
35580
35581               if (matchesDeprecatedTags) {
35582                 deprecated.push(d);
35583               }
35584             });
35585             return deprecated;
35586           }
35587         };
35588
35589         function osmLanes(entity) {
35590           if (entity.type !== 'way') return null;
35591           if (!entity.tags.highway) return null;
35592           var tags = entity.tags;
35593           var isOneWay = entity.isOneWay();
35594           var laneCount = getLaneCount(tags, isOneWay);
35595           var maxspeed = parseMaxspeed(tags);
35596           var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
35597           var forward = laneDirections.forward;
35598           var backward = laneDirections.backward;
35599           var bothways = laneDirections.bothways; // parse the piped string 'x|y|z' format
35600
35601           var turnLanes = {};
35602           turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
35603           turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
35604           turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
35605           var maxspeedLanes = {};
35606           maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
35607           maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
35608           maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
35609           var psvLanes = {};
35610           psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
35611           psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
35612           psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
35613           var busLanes = {};
35614           busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
35615           busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
35616           busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
35617           var taxiLanes = {};
35618           taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
35619           taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
35620           taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
35621           var hovLanes = {};
35622           hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
35623           hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
35624           hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
35625           var hgvLanes = {};
35626           hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
35627           hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
35628           hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
35629           var bicyclewayLanes = {};
35630           bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
35631           bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
35632           bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
35633           var lanesObj = {
35634             forward: [],
35635             backward: [],
35636             unspecified: []
35637           }; // map forward/backward/unspecified of each lane type to lanesObj
35638
35639           mapToLanesObj(lanesObj, turnLanes, 'turnLane');
35640           mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
35641           mapToLanesObj(lanesObj, psvLanes, 'psv');
35642           mapToLanesObj(lanesObj, busLanes, 'bus');
35643           mapToLanesObj(lanesObj, taxiLanes, 'taxi');
35644           mapToLanesObj(lanesObj, hovLanes, 'hov');
35645           mapToLanesObj(lanesObj, hgvLanes, 'hgv');
35646           mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
35647           return {
35648             metadata: {
35649               count: laneCount,
35650               oneway: isOneWay,
35651               forward: forward,
35652               backward: backward,
35653               bothways: bothways,
35654               turnLanes: turnLanes,
35655               maxspeed: maxspeed,
35656               maxspeedLanes: maxspeedLanes,
35657               psvLanes: psvLanes,
35658               busLanes: busLanes,
35659               taxiLanes: taxiLanes,
35660               hovLanes: hovLanes,
35661               hgvLanes: hgvLanes,
35662               bicyclewayLanes: bicyclewayLanes
35663             },
35664             lanes: lanesObj
35665           };
35666         }
35667
35668         function getLaneCount(tags, isOneWay) {
35669           var count;
35670
35671           if (tags.lanes) {
35672             count = parseInt(tags.lanes, 10);
35673
35674             if (count > 0) {
35675               return count;
35676             }
35677           }
35678
35679           switch (tags.highway) {
35680             case 'trunk':
35681             case 'motorway':
35682               count = isOneWay ? 2 : 4;
35683               break;
35684
35685             default:
35686               count = isOneWay ? 1 : 2;
35687               break;
35688           }
35689
35690           return count;
35691         }
35692
35693         function parseMaxspeed(tags) {
35694           var maxspeed = tags.maxspeed;
35695           if (!maxspeed) return;
35696           var maxspeedRegex = /^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/;
35697           if (!maxspeedRegex.test(maxspeed)) return;
35698           return parseInt(maxspeed, 10);
35699         }
35700
35701         function parseLaneDirections(tags, isOneWay, laneCount) {
35702           var forward = parseInt(tags['lanes:forward'], 10);
35703           var backward = parseInt(tags['lanes:backward'], 10);
35704           var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
35705
35706           if (parseInt(tags.oneway, 10) === -1) {
35707             forward = 0;
35708             bothways = 0;
35709             backward = laneCount;
35710           } else if (isOneWay) {
35711             forward = laneCount;
35712             bothways = 0;
35713             backward = 0;
35714           } else if (isNaN(forward) && isNaN(backward)) {
35715             backward = Math.floor((laneCount - bothways) / 2);
35716             forward = laneCount - bothways - backward;
35717           } else if (isNaN(forward)) {
35718             if (backward > laneCount - bothways) {
35719               backward = laneCount - bothways;
35720             }
35721
35722             forward = laneCount - bothways - backward;
35723           } else if (isNaN(backward)) {
35724             if (forward > laneCount - bothways) {
35725               forward = laneCount - bothways;
35726             }
35727
35728             backward = laneCount - bothways - forward;
35729           }
35730
35731           return {
35732             forward: forward,
35733             backward: backward,
35734             bothways: bothways
35735           };
35736         }
35737
35738         function parseTurnLanes(tag) {
35739           if (!tag) return;
35740           var validValues = ['left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right', 'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'];
35741           return tag.split('|').map(function (s) {
35742             if (s === '') s = 'none';
35743             return s.split(';').map(function (d) {
35744               return validValues.indexOf(d) === -1 ? 'unknown' : d;
35745             });
35746           });
35747         }
35748
35749         function parseMaxspeedLanes(tag, maxspeed) {
35750           if (!tag) return;
35751           return tag.split('|').map(function (s) {
35752             if (s === 'none') return s;
35753             var m = parseInt(s, 10);
35754             if (s === '' || m === maxspeed) return null;
35755             return isNaN(m) ? 'unknown' : m;
35756           });
35757         }
35758
35759         function parseMiscLanes(tag) {
35760           if (!tag) return;
35761           var validValues = ['yes', 'no', 'designated'];
35762           return tag.split('|').map(function (s) {
35763             if (s === '') s = 'no';
35764             return validValues.indexOf(s) === -1 ? 'unknown' : s;
35765           });
35766         }
35767
35768         function parseBicycleWay(tag) {
35769           if (!tag) return;
35770           var validValues = ['yes', 'no', 'designated', 'lane'];
35771           return tag.split('|').map(function (s) {
35772             if (s === '') s = 'no';
35773             return validValues.indexOf(s) === -1 ? 'unknown' : s;
35774           });
35775         }
35776
35777         function mapToLanesObj(lanesObj, data, key) {
35778           if (data.forward) {
35779             data.forward.forEach(function (l, i) {
35780               if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
35781               lanesObj.forward[i][key] = l;
35782             });
35783           }
35784
35785           if (data.backward) {
35786             data.backward.forEach(function (l, i) {
35787               if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
35788               lanesObj.backward[i][key] = l;
35789             });
35790           }
35791
35792           if (data.unspecified) {
35793             data.unspecified.forEach(function (l, i) {
35794               if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
35795               lanesObj.unspecified[i][key] = l;
35796             });
35797           }
35798         }
35799
35800         function osmWay() {
35801           if (!(this instanceof osmWay)) {
35802             return new osmWay().initialize(arguments);
35803           } else if (arguments.length) {
35804             this.initialize(arguments);
35805           }
35806         }
35807         osmEntity.way = osmWay;
35808         osmWay.prototype = Object.create(osmEntity.prototype);
35809         Object.assign(osmWay.prototype, {
35810           type: 'way',
35811           nodes: [],
35812           copy: function copy(resolver, copies) {
35813             if (copies[this.id]) return copies[this.id];
35814             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
35815             var nodes = this.nodes.map(function (id) {
35816               return resolver.entity(id).copy(resolver, copies).id;
35817             });
35818             copy = copy.update({
35819               nodes: nodes
35820             });
35821             copies[this.id] = copy;
35822             return copy;
35823           },
35824           extent: function extent(resolver) {
35825             return resolver["transient"](this, 'extent', function () {
35826               var extent = geoExtent();
35827
35828               for (var i = 0; i < this.nodes.length; i++) {
35829                 var node = resolver.hasEntity(this.nodes[i]);
35830
35831                 if (node) {
35832                   extent._extend(node.extent());
35833                 }
35834               }
35835
35836               return extent;
35837             });
35838           },
35839           first: function first() {
35840             return this.nodes[0];
35841           },
35842           last: function last() {
35843             return this.nodes[this.nodes.length - 1];
35844           },
35845           contains: function contains(node) {
35846             return this.nodes.indexOf(node) >= 0;
35847           },
35848           affix: function affix(node) {
35849             if (this.nodes[0] === node) return 'prefix';
35850             if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
35851           },
35852           layer: function layer() {
35853             // explicit layer tag, clamp between -10, 10..
35854             if (isFinite(this.tags.layer)) {
35855               return Math.max(-10, Math.min(+this.tags.layer, 10));
35856             } // implied layer tag..
35857
35858
35859             if (this.tags.covered === 'yes') return -1;
35860             if (this.tags.location === 'overground') return 1;
35861             if (this.tags.location === 'underground') return -1;
35862             if (this.tags.location === 'underwater') return -10;
35863             if (this.tags.power === 'line') return 10;
35864             if (this.tags.power === 'minor_line') return 10;
35865             if (this.tags.aerialway) return 10;
35866             if (this.tags.bridge) return 1;
35867             if (this.tags.cutting) return -1;
35868             if (this.tags.tunnel) return -1;
35869             if (this.tags.waterway) return -1;
35870             if (this.tags.man_made === 'pipeline') return -10;
35871             if (this.tags.boundary) return -10;
35872             return 0;
35873           },
35874           // the approximate width of the line based on its tags except its `width` tag
35875           impliedLineWidthMeters: function impliedLineWidthMeters() {
35876             var averageWidths = {
35877               highway: {
35878                 // width is for single lane
35879                 motorway: 5,
35880                 motorway_link: 5,
35881                 trunk: 4.5,
35882                 trunk_link: 4.5,
35883                 primary: 4,
35884                 secondary: 4,
35885                 tertiary: 4,
35886                 primary_link: 4,
35887                 secondary_link: 4,
35888                 tertiary_link: 4,
35889                 unclassified: 4,
35890                 road: 4,
35891                 living_street: 4,
35892                 bus_guideway: 4,
35893                 pedestrian: 4,
35894                 residential: 3.5,
35895                 service: 3.5,
35896                 track: 3,
35897                 cycleway: 2.5,
35898                 bridleway: 2,
35899                 corridor: 2,
35900                 steps: 2,
35901                 path: 1.5,
35902                 footway: 1.5
35903               },
35904               railway: {
35905                 // width includes ties and rail bed, not just track gauge
35906                 rail: 2.5,
35907                 light_rail: 2.5,
35908                 tram: 2.5,
35909                 subway: 2.5,
35910                 monorail: 2.5,
35911                 funicular: 2.5,
35912                 disused: 2.5,
35913                 preserved: 2.5,
35914                 miniature: 1.5,
35915                 narrow_gauge: 1.5
35916               },
35917               waterway: {
35918                 river: 50,
35919                 canal: 25,
35920                 stream: 5,
35921                 tidal_channel: 5,
35922                 fish_pass: 2.5,
35923                 drain: 2.5,
35924                 ditch: 1.5
35925               }
35926             };
35927
35928             for (var key in averageWidths) {
35929               if (this.tags[key] && averageWidths[key][this.tags[key]]) {
35930                 var width = averageWidths[key][this.tags[key]];
35931
35932                 if (key === 'highway') {
35933                   var laneCount = this.tags.lanes && parseInt(this.tags.lanes, 10);
35934                   if (!laneCount) laneCount = this.isOneWay() ? 1 : 2;
35935                   return width * laneCount;
35936                 }
35937
35938                 return width;
35939               }
35940             }
35941
35942             return null;
35943           },
35944           isOneWay: function isOneWay() {
35945             // explicit oneway tag..
35946             var values = {
35947               'yes': true,
35948               '1': true,
35949               '-1': true,
35950               'reversible': true,
35951               'alternating': true,
35952               'no': false,
35953               '0': false
35954             };
35955
35956             if (values[this.tags.oneway] !== undefined) {
35957               return values[this.tags.oneway];
35958             } // implied oneway tag..
35959
35960
35961             for (var key in this.tags) {
35962               if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) {
35963                 return true;
35964               }
35965             }
35966
35967             return false;
35968           },
35969           // Some identifier for tag that implies that this way is "sided",
35970           // i.e. the right side is the 'inside' (e.g. the right side of a
35971           // natural=cliff is lower).
35972           sidednessIdentifier: function sidednessIdentifier() {
35973             for (var key in this.tags) {
35974               var value = this.tags[key];
35975
35976               if (key in osmRightSideIsInsideTags && value in osmRightSideIsInsideTags[key]) {
35977                 if (osmRightSideIsInsideTags[key][value] === true) {
35978                   return key;
35979                 } else {
35980                   // if the map's value is something other than a
35981                   // literal true, we should use it so we can
35982                   // special case some keys (e.g. natural=coastline
35983                   // is handled differently to other naturals).
35984                   return osmRightSideIsInsideTags[key][value];
35985                 }
35986               }
35987             }
35988
35989             return null;
35990           },
35991           isSided: function isSided() {
35992             if (this.tags.two_sided === 'yes') {
35993               return false;
35994             }
35995
35996             return this.sidednessIdentifier() !== null;
35997           },
35998           lanes: function lanes() {
35999             return osmLanes(this);
36000           },
36001           isClosed: function isClosed() {
36002             return this.nodes.length > 1 && this.first() === this.last();
36003           },
36004           isConvex: function isConvex(resolver) {
36005             if (!this.isClosed() || this.isDegenerate()) return null;
36006             var nodes = utilArrayUniq(resolver.childNodes(this));
36007             var coords = nodes.map(function (n) {
36008               return n.loc;
36009             });
36010             var curr = 0;
36011             var prev = 0;
36012
36013             for (var i = 0; i < coords.length; i++) {
36014               var o = coords[(i + 1) % coords.length];
36015               var a = coords[i];
36016               var b = coords[(i + 2) % coords.length];
36017               var res = geoVecCross(a, b, o);
36018               curr = res > 0 ? 1 : res < 0 ? -1 : 0;
36019
36020               if (curr === 0) {
36021                 continue;
36022               } else if (prev && curr !== prev) {
36023                 return false;
36024               }
36025
36026               prev = curr;
36027             }
36028
36029             return true;
36030           },
36031           // returns an object with the tag that implies this is an area, if any
36032           tagSuggestingArea: function tagSuggestingArea() {
36033             return osmTagSuggestingArea(this.tags);
36034           },
36035           isArea: function isArea() {
36036             if (this.tags.area === 'yes') return true;
36037             if (!this.isClosed() || this.tags.area === 'no') return false;
36038             return this.tagSuggestingArea() !== null;
36039           },
36040           isDegenerate: function isDegenerate() {
36041             return new Set(this.nodes).size < (this.isArea() ? 3 : 2);
36042           },
36043           areAdjacent: function areAdjacent(n1, n2) {
36044             for (var i = 0; i < this.nodes.length; i++) {
36045               if (this.nodes[i] === n1) {
36046                 if (this.nodes[i - 1] === n2) return true;
36047                 if (this.nodes[i + 1] === n2) return true;
36048               }
36049             }
36050
36051             return false;
36052           },
36053           geometry: function geometry(graph) {
36054             return graph["transient"](this, 'geometry', function () {
36055               return this.isArea() ? 'area' : 'line';
36056             });
36057           },
36058           // returns an array of objects representing the segments between the nodes in this way
36059           segments: function segments(graph) {
36060             function segmentExtent(graph) {
36061               var n1 = graph.hasEntity(this.nodes[0]);
36062               var n2 = graph.hasEntity(this.nodes[1]);
36063               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])]]);
36064             }
36065
36066             return graph["transient"](this, 'segments', function () {
36067               var segments = [];
36068
36069               for (var i = 0; i < this.nodes.length - 1; i++) {
36070                 segments.push({
36071                   id: this.id + '-' + i,
36072                   wayId: this.id,
36073                   index: i,
36074                   nodes: [this.nodes[i], this.nodes[i + 1]],
36075                   extent: segmentExtent
36076                 });
36077               }
36078
36079               return segments;
36080             });
36081           },
36082           // If this way is not closed, append the beginning node to the end of the nodelist to close it.
36083           close: function close() {
36084             if (this.isClosed() || !this.nodes.length) return this;
36085             var nodes = this.nodes.slice();
36086             nodes = nodes.filter(noRepeatNodes);
36087             nodes.push(nodes[0]);
36088             return this.update({
36089               nodes: nodes
36090             });
36091           },
36092           // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
36093           unclose: function unclose() {
36094             if (!this.isClosed()) return this;
36095             var nodes = this.nodes.slice();
36096             var connector = this.first();
36097             var i = nodes.length - 1; // remove trailing connectors..
36098
36099             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
36100               nodes.splice(i, 1);
36101               i = nodes.length - 1;
36102             }
36103
36104             nodes = nodes.filter(noRepeatNodes);
36105             return this.update({
36106               nodes: nodes
36107             });
36108           },
36109           // Adds a node (id) in front of the node which is currently at position index.
36110           // If index is undefined, the node will be added to the end of the way for linear ways,
36111           //   or just before the final connecting node for circular ways.
36112           // Consecutive duplicates are eliminated including existing ones.
36113           // Circularity is always preserved when adding a node.
36114           addNode: function addNode(id, index) {
36115             var nodes = this.nodes.slice();
36116             var isClosed = this.isClosed();
36117             var max = isClosed ? nodes.length - 1 : nodes.length;
36118
36119             if (index === undefined) {
36120               index = max;
36121             }
36122
36123             if (index < 0 || index > max) {
36124               throw new RangeError('index ' + index + ' out of range 0..' + max);
36125             } // If this is a closed way, remove all connector nodes except the first one
36126             // (there may be duplicates) and adjust index if necessary..
36127
36128
36129             if (isClosed) {
36130               var connector = this.first(); // leading connectors..
36131
36132               var i = 1;
36133
36134               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
36135                 nodes.splice(i, 1);
36136                 if (index > i) index--;
36137               } // trailing connectors..
36138
36139
36140               i = nodes.length - 1;
36141
36142               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
36143                 nodes.splice(i, 1);
36144                 if (index > i) index--;
36145                 i = nodes.length - 1;
36146               }
36147             }
36148
36149             nodes.splice(index, 0, id);
36150             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
36151
36152             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
36153               nodes.push(nodes[0]);
36154             }
36155
36156             return this.update({
36157               nodes: nodes
36158             });
36159           },
36160           // Replaces the node which is currently at position index with the given node (id).
36161           // Consecutive duplicates are eliminated including existing ones.
36162           // Circularity is preserved when updating a node.
36163           updateNode: function updateNode(id, index) {
36164             var nodes = this.nodes.slice();
36165             var isClosed = this.isClosed();
36166             var max = nodes.length - 1;
36167
36168             if (index === undefined || index < 0 || index > max) {
36169               throw new RangeError('index ' + index + ' out of range 0..' + max);
36170             } // If this is a closed way, remove all connector nodes except the first one
36171             // (there may be duplicates) and adjust index if necessary..
36172
36173
36174             if (isClosed) {
36175               var connector = this.first(); // leading connectors..
36176
36177               var i = 1;
36178
36179               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
36180                 nodes.splice(i, 1);
36181                 if (index > i) index--;
36182               } // trailing connectors..
36183
36184
36185               i = nodes.length - 1;
36186
36187               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
36188                 nodes.splice(i, 1);
36189                 if (index === i) index = 0; // update leading connector instead
36190
36191                 i = nodes.length - 1;
36192               }
36193             }
36194
36195             nodes.splice(index, 1, id);
36196             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
36197
36198             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
36199               nodes.push(nodes[0]);
36200             }
36201
36202             return this.update({
36203               nodes: nodes
36204             });
36205           },
36206           // Replaces each occurrence of node id needle with replacement.
36207           // Consecutive duplicates are eliminated including existing ones.
36208           // Circularity is preserved.
36209           replaceNode: function replaceNode(needleID, replacementID) {
36210             var nodes = this.nodes.slice();
36211             var isClosed = this.isClosed();
36212
36213             for (var i = 0; i < nodes.length; i++) {
36214               if (nodes[i] === needleID) {
36215                 nodes[i] = replacementID;
36216               }
36217             }
36218
36219             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
36220
36221             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
36222               nodes.push(nodes[0]);
36223             }
36224
36225             return this.update({
36226               nodes: nodes
36227             });
36228           },
36229           // Removes each occurrence of node id.
36230           // Consecutive duplicates are eliminated including existing ones.
36231           // Circularity is preserved.
36232           removeNode: function removeNode(id) {
36233             var nodes = this.nodes.slice();
36234             var isClosed = this.isClosed();
36235             nodes = nodes.filter(function (node) {
36236               return node !== id;
36237             }).filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
36238
36239             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
36240               nodes.push(nodes[0]);
36241             }
36242
36243             return this.update({
36244               nodes: nodes
36245             });
36246           },
36247           asJXON: function asJXON(changeset_id) {
36248             var r = {
36249               way: {
36250                 '@id': this.osmId(),
36251                 '@version': this.version || 0,
36252                 nd: this.nodes.map(function (id) {
36253                   return {
36254                     keyAttributes: {
36255                       ref: osmEntity.id.toOSM(id)
36256                     }
36257                   };
36258                 }, this),
36259                 tag: Object.keys(this.tags).map(function (k) {
36260                   return {
36261                     keyAttributes: {
36262                       k: k,
36263                       v: this.tags[k]
36264                     }
36265                   };
36266                 }, this)
36267               }
36268             };
36269
36270             if (changeset_id) {
36271               r.way['@changeset'] = changeset_id;
36272             }
36273
36274             return r;
36275           },
36276           asGeoJSON: function asGeoJSON(resolver) {
36277             return resolver["transient"](this, 'GeoJSON', function () {
36278               var coordinates = resolver.childNodes(this).map(function (n) {
36279                 return n.loc;
36280               });
36281
36282               if (this.isArea() && this.isClosed()) {
36283                 return {
36284                   type: 'Polygon',
36285                   coordinates: [coordinates]
36286                 };
36287               } else {
36288                 return {
36289                   type: 'LineString',
36290                   coordinates: coordinates
36291                 };
36292               }
36293             });
36294           },
36295           area: function area(resolver) {
36296             return resolver["transient"](this, 'area', function () {
36297               var nodes = resolver.childNodes(this);
36298               var json = {
36299                 type: 'Polygon',
36300                 coordinates: [nodes.map(function (n) {
36301                   return n.loc;
36302                 })]
36303               };
36304
36305               if (!this.isClosed() && nodes.length) {
36306                 json.coordinates[0].push(nodes[0].loc);
36307               }
36308
36309               var area = d3_geoArea(json); // Heuristic for detecting counterclockwise winding order. Assumes
36310               // that OpenStreetMap polygons are not hemisphere-spanning.
36311
36312               if (area > 2 * Math.PI) {
36313                 json.coordinates[0] = json.coordinates[0].reverse();
36314                 area = d3_geoArea(json);
36315               }
36316
36317               return isNaN(area) ? 0 : area;
36318             });
36319           }
36320         }); // Filter function to eliminate consecutive duplicates.
36321
36322         function noRepeatNodes(node, i, arr) {
36323           return i === 0 || node !== arr[i - 1];
36324         }
36325
36326         //
36327         // 1. Relation tagged with `type=multipolygon` and no interesting tags.
36328         // 2. One and only one member with the `outer` role. Must be a way with interesting tags.
36329         // 3. No members without a role.
36330         //
36331         // Old multipolygons are no longer recommended but are still rendered as areas by iD.
36332
36333         function osmOldMultipolygonOuterMemberOfRelation(entity, graph) {
36334           if (entity.type !== 'relation' || !entity.isMultipolygon() || Object.keys(entity.tags).filter(osmIsInterestingTag).length > 1) {
36335             return false;
36336           }
36337
36338           var outerMember;
36339
36340           for (var memberIndex in entity.members) {
36341             var member = entity.members[memberIndex];
36342
36343             if (!member.role || member.role === 'outer') {
36344               if (outerMember) return false;
36345               if (member.type !== 'way') return false;
36346               if (!graph.hasEntity(member.id)) return false;
36347               outerMember = graph.entity(member.id);
36348
36349               if (Object.keys(outerMember.tags).filter(osmIsInterestingTag).length === 0) {
36350                 return false;
36351               }
36352             }
36353           }
36354
36355           return outerMember;
36356         } // For fixing up rendering of multipolygons with tags on the outer member.
36357         // https://github.com/openstreetmap/iD/issues/613
36358
36359         function osmIsOldMultipolygonOuterMember(entity, graph) {
36360           if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0) {
36361             return false;
36362           }
36363
36364           var parents = graph.parentRelations(entity);
36365           if (parents.length !== 1) return false;
36366           var parent = parents[0];
36367
36368           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
36369             return false;
36370           }
36371
36372           var members = parent.members,
36373               member;
36374
36375           for (var i = 0; i < members.length; i++) {
36376             member = members[i];
36377
36378             if (member.id === entity.id && member.role && member.role !== 'outer') {
36379               // Not outer member
36380               return false;
36381             }
36382
36383             if (member.id !== entity.id && (!member.role || member.role === 'outer')) {
36384               // Not a simple multipolygon
36385               return false;
36386             }
36387           }
36388
36389           return parent;
36390         }
36391         function osmOldMultipolygonOuterMember(entity, graph) {
36392           if (entity.type !== 'way') return false;
36393           var parents = graph.parentRelations(entity);
36394           if (parents.length !== 1) return false;
36395           var parent = parents[0];
36396
36397           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
36398             return false;
36399           }
36400
36401           var members = parent.members,
36402               member,
36403               outerMember;
36404
36405           for (var i = 0; i < members.length; i++) {
36406             member = members[i];
36407
36408             if (!member.role || member.role === 'outer') {
36409               if (outerMember) return false; // Not a simple multipolygon
36410
36411               outerMember = member;
36412             }
36413           }
36414
36415           if (!outerMember) return false;
36416           var outerEntity = graph.hasEntity(outerMember.id);
36417
36418           if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length) {
36419             return false;
36420           }
36421
36422           return outerEntity;
36423         } // Join `toJoin` array into sequences of connecting ways.
36424         // Segments which share identical start/end nodes will, as much as possible,
36425         // be connected with each other.
36426         //
36427         // The return value is a nested array. Each constituent array contains elements
36428         // of `toJoin` which have been determined to connect.
36429         //
36430         // Each consitituent array also has a `nodes` property whose value is an
36431         // ordered array of member nodes, with appropriate order reversal and
36432         // start/end coordinate de-duplication.
36433         //
36434         // Members of `toJoin` must have, at minimum, `type` and `id` properties.
36435         // Thus either an array of `osmWay`s or a relation member array may be used.
36436         //
36437         // If an member is an `osmWay`, its tags and childnodes may be reversed via
36438         // `actionReverse` in the output.
36439         //
36440         // The returned sequences array also has an `actions` array property, containing
36441         // any reversal actions that should be applied to the graph, should the calling
36442         // code attempt to actually join the given ways.
36443         //
36444         // Incomplete members (those for which `graph.hasEntity(element.id)` returns
36445         // false) and non-way members are ignored.
36446         //
36447
36448         function osmJoinWays(toJoin, graph) {
36449           function resolve(member) {
36450             return graph.childNodes(graph.entity(member.id));
36451           }
36452
36453           function reverse(item) {
36454             var action = actionReverse(item.id, {
36455               reverseOneway: true
36456             });
36457             sequences.actions.push(action);
36458             return item instanceof osmWay ? action(graph).entity(item.id) : item;
36459           } // make a copy containing only the items to join
36460
36461
36462           toJoin = toJoin.filter(function (member) {
36463             return member.type === 'way' && graph.hasEntity(member.id);
36464           }); // Are the things we are joining relation members or `osmWays`?
36465           // If `osmWays`, skip the "prefer a forward path" code below (see #4872)
36466
36467           var i;
36468           var joinAsMembers = true;
36469
36470           for (i = 0; i < toJoin.length; i++) {
36471             if (toJoin[i] instanceof osmWay) {
36472               joinAsMembers = false;
36473               break;
36474             }
36475           }
36476
36477           var sequences = [];
36478           sequences.actions = [];
36479
36480           while (toJoin.length) {
36481             // start a new sequence
36482             var item = toJoin.shift();
36483             var currWays = [item];
36484             var currNodes = resolve(item).slice(); // add to it
36485
36486             while (toJoin.length) {
36487               var start = currNodes[0];
36488               var end = currNodes[currNodes.length - 1];
36489               var fn = null;
36490               var nodes = null; // Find the next way/member to join.
36491
36492               for (i = 0; i < toJoin.length; i++) {
36493                 item = toJoin[i];
36494                 nodes = resolve(item); // (for member ordering only, not way ordering - see #4872)
36495                 // Strongly prefer to generate a forward path that preserves the order
36496                 // of the members array. For multipolygons and most relations, member
36497                 // order does not matter - but for routes, it does. (see #4589)
36498                 // If we started this sequence backwards (i.e. next member way attaches to
36499                 // the start node and not the end node), reverse the initial way before continuing.
36500
36501                 if (joinAsMembers && currWays.length === 1 && nodes[0] !== end && nodes[nodes.length - 1] !== end && (nodes[nodes.length - 1] === start || nodes[0] === start)) {
36502                   currWays[0] = reverse(currWays[0]);
36503                   currNodes.reverse();
36504                   start = currNodes[0];
36505                   end = currNodes[currNodes.length - 1];
36506                 }
36507
36508                 if (nodes[0] === end) {
36509                   fn = currNodes.push; // join to end
36510
36511                   nodes = nodes.slice(1);
36512                   break;
36513                 } else if (nodes[nodes.length - 1] === end) {
36514                   fn = currNodes.push; // join to end
36515
36516                   nodes = nodes.slice(0, -1).reverse();
36517                   item = reverse(item);
36518                   break;
36519                 } else if (nodes[nodes.length - 1] === start) {
36520                   fn = currNodes.unshift; // join to beginning
36521
36522                   nodes = nodes.slice(0, -1);
36523                   break;
36524                 } else if (nodes[0] === start) {
36525                   fn = currNodes.unshift; // join to beginning
36526
36527                   nodes = nodes.slice(1).reverse();
36528                   item = reverse(item);
36529                   break;
36530                 } else {
36531                   fn = nodes = null;
36532                 }
36533               }
36534
36535               if (!nodes) {
36536                 // couldn't find a joinable way/member
36537                 break;
36538               }
36539
36540               fn.apply(currWays, [item]);
36541               fn.apply(currNodes, nodes);
36542               toJoin.splice(i, 1);
36543             }
36544
36545             currWays.nodes = currNodes;
36546             sequences.push(currWays);
36547           }
36548
36549           return sequences;
36550         }
36551
36552         function actionAddMember(relationId, member, memberIndex, insertPair) {
36553           return function action(graph) {
36554             var relation = graph.entity(relationId); // There are some special rules for Public Transport v2 routes.
36555
36556             var isPTv2 = /stop|platform/.test(member.role);
36557
36558             if ((isNaN(memberIndex) || insertPair) && member.type === 'way' && !isPTv2) {
36559               // Try to perform sensible inserts based on how the ways join together
36560               graph = addWayMember(relation, graph);
36561             } else {
36562               // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
36563               // Stops and Platforms for PTv2 should be ordered first.
36564               // hack: We do not currently have the ability to place them in the exactly correct order.
36565               if (isPTv2 && isNaN(memberIndex)) {
36566                 memberIndex = 0;
36567               }
36568
36569               graph = graph.replace(relation.addMember(member, memberIndex));
36570             }
36571
36572             return graph;
36573           }; // Add a way member into the relation "wherever it makes sense".
36574           // In this situation we were not supplied a memberIndex.
36575
36576           function addWayMember(relation, graph) {
36577             var groups, tempWay, item, i, j, k; // remove PTv2 stops and platforms before doing anything.
36578
36579             var PTv2members = [];
36580             var members = [];
36581
36582             for (i = 0; i < relation.members.length; i++) {
36583               var m = relation.members[i];
36584
36585               if (/stop|platform/.test(m.role)) {
36586                 PTv2members.push(m);
36587               } else {
36588                 members.push(m);
36589               }
36590             }
36591
36592             relation = relation.update({
36593               members: members
36594             });
36595
36596             if (insertPair) {
36597               // We're adding a member that must stay paired with an existing member.
36598               // (This feature is used by `actionSplit`)
36599               //
36600               // This is tricky because the members may exist multiple times in the
36601               // member list, and with different A-B/B-A ordering and different roles.
36602               // (e.g. a bus route that loops out and back - #4589).
36603               //
36604               // Replace the existing member with a temporary way,
36605               // so that `osmJoinWays` can treat the pair like a single way.
36606               tempWay = osmWay({
36607                 id: 'wTemp',
36608                 nodes: insertPair.nodes
36609               });
36610               graph = graph.replace(tempWay);
36611               var tempMember = {
36612                 id: tempWay.id,
36613                 type: 'way',
36614                 role: member.role
36615               };
36616               var tempRelation = relation.replaceMember({
36617                 id: insertPair.originalID
36618               }, tempMember, true);
36619               groups = utilArrayGroupBy(tempRelation.members, 'type');
36620               groups.way = groups.way || [];
36621             } else {
36622               // Add the member anywhere, one time. Just push and let `osmJoinWays` decide where to put it.
36623               groups = utilArrayGroupBy(relation.members, 'type');
36624               groups.way = groups.way || [];
36625               groups.way.push(member);
36626             }
36627
36628             members = withIndex(groups.way);
36629             var joined = osmJoinWays(members, graph); // `joined` might not contain all of the way members,
36630             // But will contain only the completed (downloaded) members
36631
36632             for (i = 0; i < joined.length; i++) {
36633               var segment = joined[i];
36634               var nodes = segment.nodes.slice();
36635               var startIndex = segment[0].index; // j = array index in `members` where this segment starts
36636
36637               for (j = 0; j < members.length; j++) {
36638                 if (members[j].index === startIndex) {
36639                   break;
36640                 }
36641               } // k = each member in segment
36642
36643
36644               for (k = 0; k < segment.length; k++) {
36645                 item = segment[k];
36646                 var way = graph.entity(item.id); // If this is a paired item, generate members in correct order and role
36647
36648                 if (tempWay && item.id === tempWay.id) {
36649                   if (nodes[0].id === insertPair.nodes[0]) {
36650                     item.pair = [{
36651                       id: insertPair.originalID,
36652                       type: 'way',
36653                       role: item.role
36654                     }, {
36655                       id: insertPair.insertedID,
36656                       type: 'way',
36657                       role: item.role
36658                     }];
36659                   } else {
36660                     item.pair = [{
36661                       id: insertPair.insertedID,
36662                       type: 'way',
36663                       role: item.role
36664                     }, {
36665                       id: insertPair.originalID,
36666                       type: 'way',
36667                       role: item.role
36668                     }];
36669                   }
36670                 } // reorder `members` if necessary
36671
36672
36673                 if (k > 0) {
36674                   if (j + k >= members.length || item.index !== members[j + k].index) {
36675                     moveMember(members, item.index, j + k);
36676                   }
36677                 }
36678
36679                 nodes.splice(0, way.nodes.length - 1);
36680               }
36681             }
36682
36683             if (tempWay) {
36684               graph = graph.remove(tempWay);
36685             } // Final pass: skip dead items, split pairs, remove index properties
36686
36687
36688             var wayMembers = [];
36689
36690             for (i = 0; i < members.length; i++) {
36691               item = members[i];
36692               if (item.index === -1) continue;
36693
36694               if (item.pair) {
36695                 wayMembers.push(item.pair[0]);
36696                 wayMembers.push(item.pair[1]);
36697               } else {
36698                 wayMembers.push(utilObjectOmit(item, ['index']));
36699               }
36700             } // Put stops and platforms first, then nodes, ways, relations
36701             // This is recommended for Public Transport v2 routes:
36702             // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
36703
36704
36705             var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
36706             return graph.replace(relation.update({
36707               members: newMembers
36708             })); // `moveMember()` changes the `members` array in place by splicing
36709             // the item with `.index = findIndex` to where it belongs,
36710             // and marking the old position as "dead" with `.index = -1`
36711             //
36712             // j=5, k=0                jk
36713             // segment                 5 4 7 6
36714             // members       0 1 2 3 4 5 6 7 8 9        keep 5 in j+k
36715             //
36716             // j=5, k=1                j k
36717             // segment                 5 4 7 6
36718             // members       0 1 2 3 4 5 6 7 8 9        move 4 to j+k
36719             // members       0 1 2 3 x 5 4 6 7 8 9      moved
36720             //
36721             // j=5, k=2                j   k
36722             // segment                 5 4 7 6
36723             // members       0 1 2 3 x 5 4 6 7 8 9      move 7 to j+k
36724             // members       0 1 2 3 x 5 4 7 6 x 8 9    moved
36725             //
36726             // j=5, k=3                j     k
36727             // segment                 5 4 7 6
36728             // members       0 1 2 3 x 5 4 7 6 x 8 9    keep 6 in j+k
36729             //
36730
36731             function moveMember(arr, findIndex, toIndex) {
36732               var i;
36733
36734               for (i = 0; i < arr.length; i++) {
36735                 if (arr[i].index === findIndex) {
36736                   break;
36737                 }
36738               }
36739
36740               var item = Object.assign({}, arr[i]); // shallow copy
36741
36742               arr[i].index = -1; // mark as dead
36743
36744               item.index = toIndex;
36745               arr.splice(toIndex, 0, item);
36746             } // This is the same as `Relation.indexedMembers`,
36747             // Except we don't want to index all the members, only the ways
36748
36749
36750             function withIndex(arr) {
36751               var result = new Array(arr.length);
36752
36753               for (var i = 0; i < arr.length; i++) {
36754                 result[i] = Object.assign({}, arr[i]); // shallow copy
36755
36756                 result[i].index = i;
36757               }
36758
36759               return result;
36760             }
36761           }
36762         }
36763
36764         function actionAddMidpoint(midpoint, node) {
36765           return function (graph) {
36766             graph = graph.replace(node.move(midpoint.loc));
36767             var parents = utilArrayIntersection(graph.parentWays(graph.entity(midpoint.edge[0])), graph.parentWays(graph.entity(midpoint.edge[1])));
36768             parents.forEach(function (way) {
36769               for (var i = 0; i < way.nodes.length - 1; i++) {
36770                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
36771                   graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1)); // Add only one midpoint on doubled-back segments,
36772                   // turning them into self-intersections.
36773
36774                   return;
36775                 }
36776               }
36777             });
36778             return graph;
36779           };
36780         }
36781
36782         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
36783         function actionAddVertex(wayId, nodeId, index) {
36784           return function (graph) {
36785             return graph.replace(graph.entity(wayId).addNode(nodeId, index));
36786           };
36787         }
36788
36789         function actionChangeMember(relationId, member, memberIndex) {
36790           return function (graph) {
36791             return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
36792           };
36793         }
36794
36795         function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefaults) {
36796           return function action(graph) {
36797             var entity = graph.entity(entityID);
36798             var geometry = entity.geometry(graph);
36799             var tags = entity.tags; // preserve tags that the new preset might care about, if any
36800
36801             if (oldPreset) tags = oldPreset.unsetTags(tags, geometry, newPreset && newPreset.addTags ? Object.keys(newPreset.addTags) : null);
36802             if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults);
36803             return graph.replace(entity.update({
36804               tags: tags
36805             }));
36806           };
36807         }
36808
36809         function actionChangeTags(entityId, tags) {
36810           return function (graph) {
36811             var entity = graph.entity(entityId);
36812             return graph.replace(entity.update({
36813               tags: tags
36814             }));
36815           };
36816         }
36817
36818         function osmNode() {
36819           if (!(this instanceof osmNode)) {
36820             return new osmNode().initialize(arguments);
36821           } else if (arguments.length) {
36822             this.initialize(arguments);
36823           }
36824         }
36825         osmEntity.node = osmNode;
36826         osmNode.prototype = Object.create(osmEntity.prototype);
36827         Object.assign(osmNode.prototype, {
36828           type: 'node',
36829           loc: [9999, 9999],
36830           extent: function extent() {
36831             return new geoExtent(this.loc);
36832           },
36833           geometry: function geometry(graph) {
36834             return graph["transient"](this, 'geometry', function () {
36835               return graph.isPoi(this) ? 'point' : 'vertex';
36836             });
36837           },
36838           move: function move(loc) {
36839             return this.update({
36840               loc: loc
36841             });
36842           },
36843           isDegenerate: function isDegenerate() {
36844             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);
36845           },
36846           // Inspect tags and geometry to determine which direction(s) this node/vertex points
36847           directions: function directions(resolver, projection) {
36848             var val;
36849             var i; // which tag to use?
36850
36851             if (this.isHighwayIntersection(resolver) && (this.tags.stop || '').toLowerCase() === 'all') {
36852               // all-way stop tag on a highway intersection
36853               val = 'all';
36854             } else {
36855               // generic direction tag
36856               val = (this.tags.direction || '').toLowerCase(); // better suffix-style direction tag
36857
36858               var re = /:direction$/i;
36859               var keys = Object.keys(this.tags);
36860
36861               for (i = 0; i < keys.length; i++) {
36862                 if (re.test(keys[i])) {
36863                   val = this.tags[keys[i]].toLowerCase();
36864                   break;
36865                 }
36866               }
36867             }
36868
36869             if (val === '') return [];
36870             var cardinal = {
36871               north: 0,
36872               n: 0,
36873               northnortheast: 22,
36874               nne: 22,
36875               northeast: 45,
36876               ne: 45,
36877               eastnortheast: 67,
36878               ene: 67,
36879               east: 90,
36880               e: 90,
36881               eastsoutheast: 112,
36882               ese: 112,
36883               southeast: 135,
36884               se: 135,
36885               southsoutheast: 157,
36886               sse: 157,
36887               south: 180,
36888               s: 180,
36889               southsouthwest: 202,
36890               ssw: 202,
36891               southwest: 225,
36892               sw: 225,
36893               westsouthwest: 247,
36894               wsw: 247,
36895               west: 270,
36896               w: 270,
36897               westnorthwest: 292,
36898               wnw: 292,
36899               northwest: 315,
36900               nw: 315,
36901               northnorthwest: 337,
36902               nnw: 337
36903             };
36904             var values = val.split(';');
36905             var results = [];
36906             values.forEach(function (v) {
36907               // swap cardinal for numeric directions
36908               if (cardinal[v] !== undefined) {
36909                 v = cardinal[v];
36910               } // numeric direction - just add to results
36911
36912
36913               if (v !== '' && !isNaN(+v)) {
36914                 results.push(+v);
36915                 return;
36916               } // string direction - inspect parent ways
36917
36918
36919               var lookBackward = this.tags['traffic_sign:backward'] || v === 'backward' || v === 'both' || v === 'all';
36920               var lookForward = this.tags['traffic_sign:forward'] || v === 'forward' || v === 'both' || v === 'all';
36921               if (!lookForward && !lookBackward) return;
36922               var nodeIds = {};
36923               resolver.parentWays(this).forEach(function (parent) {
36924                 var nodes = parent.nodes;
36925
36926                 for (i = 0; i < nodes.length; i++) {
36927                   if (nodes[i] === this.id) {
36928                     // match current entity
36929                     if (lookForward && i > 0) {
36930                       nodeIds[nodes[i - 1]] = true; // look back to prev node
36931                     }
36932
36933                     if (lookBackward && i < nodes.length - 1) {
36934                       nodeIds[nodes[i + 1]] = true; // look ahead to next node
36935                     }
36936                   }
36937                 }
36938               }, this);
36939               Object.keys(nodeIds).forEach(function (nodeId) {
36940                 // +90 because geoAngle returns angle from X axis, not Y (north)
36941                 results.push(geoAngle(this, resolver.entity(nodeId), projection) * (180 / Math.PI) + 90);
36942               }, this);
36943             }, this);
36944             return utilArrayUniq(results);
36945           },
36946           isEndpoint: function isEndpoint(resolver) {
36947             return resolver["transient"](this, 'isEndpoint', function () {
36948               var id = this.id;
36949               return resolver.parentWays(this).filter(function (parent) {
36950                 return !parent.isClosed() && !!parent.affix(id);
36951               }).length > 0;
36952             });
36953           },
36954           isConnected: function isConnected(resolver) {
36955             return resolver["transient"](this, 'isConnected', function () {
36956               var parents = resolver.parentWays(this);
36957
36958               if (parents.length > 1) {
36959                 // vertex is connected to multiple parent ways
36960                 for (var i in parents) {
36961                   if (parents[i].geometry(resolver) === 'line' && parents[i].hasInterestingTags()) return true;
36962                 }
36963               } else if (parents.length === 1) {
36964                 var way = parents[0];
36965                 var nodes = way.nodes.slice();
36966
36967                 if (way.isClosed()) {
36968                   nodes.pop();
36969                 } // ignore connecting node if closed
36970                 // return true if vertex appears multiple times (way is self intersecting)
36971
36972
36973                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
36974               }
36975
36976               return false;
36977             });
36978           },
36979           parentIntersectionWays: function parentIntersectionWays(resolver) {
36980             return resolver["transient"](this, 'parentIntersectionWays', function () {
36981               return resolver.parentWays(this).filter(function (parent) {
36982                 return (parent.tags.highway || parent.tags.waterway || parent.tags.railway || parent.tags.aeroway) && parent.geometry(resolver) === 'line';
36983               });
36984             });
36985           },
36986           isIntersection: function isIntersection(resolver) {
36987             return this.parentIntersectionWays(resolver).length > 1;
36988           },
36989           isHighwayIntersection: function isHighwayIntersection(resolver) {
36990             return resolver["transient"](this, 'isHighwayIntersection', function () {
36991               return resolver.parentWays(this).filter(function (parent) {
36992                 return parent.tags.highway && parent.geometry(resolver) === 'line';
36993               }).length > 1;
36994             });
36995           },
36996           isOnAddressLine: function isOnAddressLine(resolver) {
36997             return resolver["transient"](this, 'isOnAddressLine', function () {
36998               return resolver.parentWays(this).filter(function (parent) {
36999                 return parent.tags.hasOwnProperty('addr:interpolation') && parent.geometry(resolver) === 'line';
37000               }).length > 0;
37001             });
37002           },
37003           asJXON: function asJXON(changeset_id) {
37004             var r = {
37005               node: {
37006                 '@id': this.osmId(),
37007                 '@lon': this.loc[0],
37008                 '@lat': this.loc[1],
37009                 '@version': this.version || 0,
37010                 tag: Object.keys(this.tags).map(function (k) {
37011                   return {
37012                     keyAttributes: {
37013                       k: k,
37014                       v: this.tags[k]
37015                     }
37016                   };
37017                 }, this)
37018               }
37019             };
37020             if (changeset_id) r.node['@changeset'] = changeset_id;
37021             return r;
37022           },
37023           asGeoJSON: function asGeoJSON() {
37024             return {
37025               type: 'Point',
37026               coordinates: this.loc
37027             };
37028           }
37029         });
37030
37031         function actionCircularize(wayId, projection, maxAngle) {
37032           maxAngle = (maxAngle || 20) * Math.PI / 180;
37033
37034           var action = function action(graph, t) {
37035             if (t === null || !isFinite(t)) t = 1;
37036             t = Math.min(Math.max(+t, 0), 1);
37037             var way = graph.entity(wayId);
37038             var origNodes = {};
37039             graph.childNodes(way).forEach(function (node) {
37040               if (!origNodes[node.id]) origNodes[node.id] = node;
37041             });
37042
37043             if (!way.isConvex(graph)) {
37044               graph = action.makeConvex(graph);
37045             }
37046
37047             var nodes = utilArrayUniq(graph.childNodes(way));
37048             var keyNodes = nodes.filter(function (n) {
37049               return graph.parentWays(n).length !== 1;
37050             });
37051             var points = nodes.map(function (n) {
37052               return projection(n.loc);
37053             });
37054             var keyPoints = keyNodes.map(function (n) {
37055               return projection(n.loc);
37056             });
37057             var centroid = points.length === 2 ? geoVecInterp(points[0], points[1], 0.5) : d3_polygonCentroid(points);
37058             var radius = d3_median(points, function (p) {
37059               return geoVecLength(centroid, p);
37060             });
37061             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
37062             var ids, i, j, k; // we need at least two key nodes for the algorithm to work
37063
37064             if (!keyNodes.length) {
37065               keyNodes = [nodes[0]];
37066               keyPoints = [points[0]];
37067             }
37068
37069             if (keyNodes.length === 1) {
37070               var index = nodes.indexOf(keyNodes[0]);
37071               var oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
37072               keyNodes.push(nodes[oppositeIndex]);
37073               keyPoints.push(points[oppositeIndex]);
37074             } // key points and nodes are those connected to the ways,
37075             // they are projected onto the circle, in between nodes are moved
37076             // to constant intervals between key nodes, extra in between nodes are
37077             // added if necessary.
37078
37079
37080             for (i = 0; i < keyPoints.length; i++) {
37081               var nextKeyNodeIndex = (i + 1) % keyNodes.length;
37082               var startNode = keyNodes[i];
37083               var endNode = keyNodes[nextKeyNodeIndex];
37084               var startNodeIndex = nodes.indexOf(startNode);
37085               var endNodeIndex = nodes.indexOf(endNode);
37086               var numberNewPoints = -1;
37087               var indexRange = endNodeIndex - startNodeIndex;
37088               var nearNodes = {};
37089               var inBetweenNodes = [];
37090               var startAngle, endAngle, totalAngle, eachAngle;
37091               var angle, loc, node, origNode;
37092
37093               if (indexRange < 0) {
37094                 indexRange += nodes.length;
37095               } // position this key node
37096
37097
37098               var distance = geoVecLength(centroid, keyPoints[i]) || 1e-4;
37099               keyPoints[i] = [centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius, centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
37100               loc = projection.invert(keyPoints[i]);
37101               node = keyNodes[i];
37102               origNode = origNodes[node.id];
37103               node = node.move(geoVecInterp(origNode.loc, loc, t));
37104               graph = graph.replace(node); // figure out the between delta angle we want to match to
37105
37106               startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
37107               endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
37108               totalAngle = endAngle - startAngle; // detects looping around -pi/pi
37109
37110               if (totalAngle * sign > 0) {
37111                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
37112               }
37113
37114               do {
37115                 numberNewPoints++;
37116                 eachAngle = totalAngle / (indexRange + numberNewPoints);
37117               } while (Math.abs(eachAngle) > maxAngle); // move existing nodes
37118
37119
37120               for (j = 1; j < indexRange; j++) {
37121                 angle = startAngle + j * eachAngle;
37122                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]);
37123                 node = nodes[(j + startNodeIndex) % nodes.length];
37124                 origNode = origNodes[node.id];
37125                 nearNodes[node.id] = angle;
37126                 node = node.move(geoVecInterp(origNode.loc, loc, t));
37127                 graph = graph.replace(node);
37128               } // add new in between nodes if necessary
37129
37130
37131               for (j = 0; j < numberNewPoints; j++) {
37132                 angle = startAngle + (indexRange + j) * eachAngle;
37133                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]); // choose a nearnode to use as the original
37134
37135                 var min = Infinity;
37136
37137                 for (var nodeId in nearNodes) {
37138                   var nearAngle = nearNodes[nodeId];
37139                   var dist = Math.abs(nearAngle - angle);
37140
37141                   if (dist < min) {
37142                     min = dist;
37143                     origNode = origNodes[nodeId];
37144                   }
37145                 }
37146
37147                 node = osmNode({
37148                   loc: geoVecInterp(origNode.loc, loc, t)
37149                 });
37150                 graph = graph.replace(node);
37151                 nodes.splice(endNodeIndex + j, 0, node);
37152                 inBetweenNodes.push(node.id);
37153               } // Check for other ways that share these keyNodes..
37154               // If keyNodes are adjacent in both ways,
37155               // we can add inBetweenNodes to that shared way too..
37156
37157
37158               if (indexRange === 1 && inBetweenNodes.length) {
37159                 var startIndex1 = way.nodes.lastIndexOf(startNode.id);
37160                 var endIndex1 = way.nodes.lastIndexOf(endNode.id);
37161                 var wayDirection1 = endIndex1 - startIndex1;
37162
37163                 if (wayDirection1 < -1) {
37164                   wayDirection1 = 1;
37165                 }
37166
37167                 var parentWays = graph.parentWays(keyNodes[i]);
37168
37169                 for (j = 0; j < parentWays.length; j++) {
37170                   var sharedWay = parentWays[j];
37171                   if (sharedWay === way) continue;
37172
37173                   if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
37174                     var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id);
37175                     var endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id);
37176                     var wayDirection2 = endIndex2 - startIndex2;
37177                     var insertAt = endIndex2;
37178
37179                     if (wayDirection2 < -1) {
37180                       wayDirection2 = 1;
37181                     }
37182
37183                     if (wayDirection1 !== wayDirection2) {
37184                       inBetweenNodes.reverse();
37185                       insertAt = startIndex2;
37186                     }
37187
37188                     for (k = 0; k < inBetweenNodes.length; k++) {
37189                       sharedWay = sharedWay.addNode(inBetweenNodes[k], insertAt + k);
37190                     }
37191
37192                     graph = graph.replace(sharedWay);
37193                   }
37194                 }
37195               }
37196             } // update the way to have all the new nodes
37197
37198
37199             ids = nodes.map(function (n) {
37200               return n.id;
37201             });
37202             ids.push(ids[0]);
37203             way = way.update({
37204               nodes: ids
37205             });
37206             graph = graph.replace(way);
37207             return graph;
37208           };
37209
37210           action.makeConvex = function (graph) {
37211             var way = graph.entity(wayId);
37212             var nodes = utilArrayUniq(graph.childNodes(way));
37213             var points = nodes.map(function (n) {
37214               return projection(n.loc);
37215             });
37216             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
37217             var hull = d3_polygonHull(points);
37218             var i, j; // D3 convex hulls go counterclockwise..
37219
37220             if (sign === -1) {
37221               nodes.reverse();
37222               points.reverse();
37223             }
37224
37225             for (i = 0; i < hull.length - 1; i++) {
37226               var startIndex = points.indexOf(hull[i]);
37227               var endIndex = points.indexOf(hull[i + 1]);
37228               var indexRange = endIndex - startIndex;
37229
37230               if (indexRange < 0) {
37231                 indexRange += nodes.length;
37232               } // move interior nodes to the surface of the convex hull..
37233
37234
37235               for (j = 1; j < indexRange; j++) {
37236                 var point = geoVecInterp(hull[i], hull[i + 1], j / indexRange);
37237                 var node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
37238                 graph = graph.replace(node);
37239               }
37240             }
37241
37242             return graph;
37243           };
37244
37245           action.disabled = function (graph) {
37246             if (!graph.entity(wayId).isClosed()) {
37247               return 'not_closed';
37248             } //disable when already circular
37249
37250
37251             var way = graph.entity(wayId);
37252             var nodes = utilArrayUniq(graph.childNodes(way));
37253             var points = nodes.map(function (n) {
37254               return projection(n.loc);
37255             });
37256             var hull = d3_polygonHull(points);
37257             var epsilonAngle = Math.PI / 180;
37258
37259             if (hull.length !== points.length || hull.length < 3) {
37260               return false;
37261             }
37262
37263             var centroid = d3_polygonCentroid(points);
37264             var radius = geoVecLengthSquare(centroid, points[0]);
37265             var i, actualPoint; // compare distances between centroid and points
37266
37267             for (i = 0; i < hull.length; i++) {
37268               actualPoint = hull[i];
37269               var actualDist = geoVecLengthSquare(actualPoint, centroid);
37270               var diff = Math.abs(actualDist - radius); //compare distances with epsilon-error (5%)
37271
37272               if (diff > 0.05 * radius) {
37273                 return false;
37274               }
37275             } //check if central angles are smaller than maxAngle
37276
37277
37278             for (i = 0; i < hull.length; i++) {
37279               actualPoint = hull[i];
37280               var nextPoint = hull[(i + 1) % hull.length];
37281               var startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
37282               var endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
37283               var angle = endAngle - startAngle;
37284
37285               if (angle < 0) {
37286                 angle = -angle;
37287               }
37288
37289               if (angle > Math.PI) {
37290                 angle = 2 * Math.PI - angle;
37291               }
37292
37293               if (angle > maxAngle + epsilonAngle) {
37294                 return false;
37295               }
37296             }
37297
37298             return 'already_circular';
37299           };
37300
37301           action.transitionable = true;
37302           return action;
37303         }
37304
37305         function actionDeleteWay(wayID) {
37306           function canDeleteNode(node, graph) {
37307             // don't delete nodes still attached to ways or relations
37308             if (graph.parentWays(node).length || graph.parentRelations(node).length) return false;
37309             var geometries = osmNodeGeometriesForTags(node.tags); // don't delete if this node can be a standalone point
37310
37311             if (geometries.point) return false; // delete if this node only be a vertex
37312
37313             if (geometries.vertex) return true; // iD doesn't know if this should be a point or vertex,
37314             // so only delete if there are no interesting tags
37315
37316             return !node.hasInterestingTags();
37317           }
37318
37319           var action = function action(graph) {
37320             var way = graph.entity(wayID);
37321             graph.parentRelations(way).forEach(function (parent) {
37322               parent = parent.removeMembersWithID(wayID);
37323               graph = graph.replace(parent);
37324
37325               if (parent.isDegenerate()) {
37326                 graph = actionDeleteRelation(parent.id)(graph);
37327               }
37328             });
37329             new Set(way.nodes).forEach(function (nodeID) {
37330               graph = graph.replace(way.removeNode(nodeID));
37331               var node = graph.entity(nodeID);
37332
37333               if (canDeleteNode(node, graph)) {
37334                 graph = graph.remove(node);
37335               }
37336             });
37337             return graph.remove(way);
37338           };
37339
37340           return action;
37341         }
37342
37343         function actionDeleteMultiple(ids) {
37344           var actions = {
37345             way: actionDeleteWay,
37346             node: actionDeleteNode,
37347             relation: actionDeleteRelation
37348           };
37349
37350           var action = function action(graph) {
37351             ids.forEach(function (id) {
37352               if (graph.hasEntity(id)) {
37353                 // It may have been deleted already.
37354                 graph = actions[graph.entity(id).type](id)(graph);
37355               }
37356             });
37357             return graph;
37358           };
37359
37360           return action;
37361         }
37362
37363         function actionDeleteRelation(relationID, allowUntaggedMembers) {
37364           function canDeleteEntity(entity, graph) {
37365             return !graph.parentWays(entity).length && !graph.parentRelations(entity).length && !entity.hasInterestingTags() && !allowUntaggedMembers;
37366           }
37367
37368           var action = function action(graph) {
37369             var relation = graph.entity(relationID);
37370             graph.parentRelations(relation).forEach(function (parent) {
37371               parent = parent.removeMembersWithID(relationID);
37372               graph = graph.replace(parent);
37373
37374               if (parent.isDegenerate()) {
37375                 graph = actionDeleteRelation(parent.id)(graph);
37376               }
37377             });
37378             var memberIDs = utilArrayUniq(relation.members.map(function (m) {
37379               return m.id;
37380             }));
37381             memberIDs.forEach(function (memberID) {
37382               graph = graph.replace(relation.removeMembersWithID(memberID));
37383               var entity = graph.entity(memberID);
37384
37385               if (canDeleteEntity(entity, graph)) {
37386                 graph = actionDeleteMultiple([memberID])(graph);
37387               }
37388             });
37389             return graph.remove(relation);
37390           };
37391
37392           return action;
37393         }
37394
37395         function actionDeleteNode(nodeId) {
37396           var action = function action(graph) {
37397             var node = graph.entity(nodeId);
37398             graph.parentWays(node).forEach(function (parent) {
37399               parent = parent.removeNode(nodeId);
37400               graph = graph.replace(parent);
37401
37402               if (parent.isDegenerate()) {
37403                 graph = actionDeleteWay(parent.id)(graph);
37404               }
37405             });
37406             graph.parentRelations(node).forEach(function (parent) {
37407               parent = parent.removeMembersWithID(nodeId);
37408               graph = graph.replace(parent);
37409
37410               if (parent.isDegenerate()) {
37411                 graph = actionDeleteRelation(parent.id)(graph);
37412               }
37413             });
37414             return graph.remove(node);
37415           };
37416
37417           return action;
37418         }
37419
37420         //
37421         // First choose a node to be the survivor, with preference given
37422         // to an existing (not new) node.
37423         //
37424         // Tags and relation memberships of of non-surviving nodes are merged
37425         // to the survivor.
37426         //
37427         // This is the inverse of `iD.actionDisconnect`.
37428         //
37429         // Reference:
37430         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
37431         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
37432         //
37433
37434         function actionConnect(nodeIDs) {
37435           var action = function action(graph) {
37436             var survivor;
37437             var node;
37438             var parents;
37439             var i, j; // Choose a survivor node, prefer an existing (not new) node - #4974
37440
37441             for (i = 0; i < nodeIDs.length; i++) {
37442               survivor = graph.entity(nodeIDs[i]);
37443               if (survivor.version) break; // found one
37444             } // Replace all non-surviving nodes with the survivor and merge tags.
37445
37446
37447             for (i = 0; i < nodeIDs.length; i++) {
37448               node = graph.entity(nodeIDs[i]);
37449               if (node.id === survivor.id) continue;
37450               parents = graph.parentWays(node);
37451
37452               for (j = 0; j < parents.length; j++) {
37453                 graph = graph.replace(parents[j].replaceNode(node.id, survivor.id));
37454               }
37455
37456               parents = graph.parentRelations(node);
37457
37458               for (j = 0; j < parents.length; j++) {
37459                 graph = graph.replace(parents[j].replaceMember(node, survivor));
37460               }
37461
37462               survivor = survivor.mergeTags(node.tags);
37463               graph = actionDeleteNode(node.id)(graph);
37464             }
37465
37466             graph = graph.replace(survivor); // find and delete any degenerate ways created by connecting adjacent vertices
37467
37468             parents = graph.parentWays(survivor);
37469
37470             for (i = 0; i < parents.length; i++) {
37471               if (parents[i].isDegenerate()) {
37472                 graph = actionDeleteWay(parents[i].id)(graph);
37473               }
37474             }
37475
37476             return graph;
37477           };
37478
37479           action.disabled = function (graph) {
37480             var seen = {};
37481             var restrictionIDs = [];
37482             var survivor;
37483             var node, way;
37484             var relations, relation, role;
37485             var i, j, k; // Choose a survivor node, prefer an existing (not new) node - #4974
37486
37487             for (i = 0; i < nodeIDs.length; i++) {
37488               survivor = graph.entity(nodeIDs[i]);
37489               if (survivor.version) break; // found one
37490             } // 1. disable if the nodes being connected have conflicting relation roles
37491
37492
37493             for (i = 0; i < nodeIDs.length; i++) {
37494               node = graph.entity(nodeIDs[i]);
37495               relations = graph.parentRelations(node);
37496
37497               for (j = 0; j < relations.length; j++) {
37498                 relation = relations[j];
37499                 role = relation.memberById(node.id).role || ''; // if this node is a via node in a restriction, remember for later
37500
37501                 if (relation.hasFromViaTo()) {
37502                   restrictionIDs.push(relation.id);
37503                 }
37504
37505                 if (seen[relation.id] !== undefined && seen[relation.id] !== role) {
37506                   return 'relation';
37507                 } else {
37508                   seen[relation.id] = role;
37509                 }
37510               }
37511             } // gather restrictions for parent ways
37512
37513
37514             for (i = 0; i < nodeIDs.length; i++) {
37515               node = graph.entity(nodeIDs[i]);
37516               var parents = graph.parentWays(node);
37517
37518               for (j = 0; j < parents.length; j++) {
37519                 var parent = parents[j];
37520                 relations = graph.parentRelations(parent);
37521
37522                 for (k = 0; k < relations.length; k++) {
37523                   relation = relations[k];
37524
37525                   if (relation.hasFromViaTo()) {
37526                     restrictionIDs.push(relation.id);
37527                   }
37528                 }
37529               }
37530             } // test restrictions
37531
37532
37533             restrictionIDs = utilArrayUniq(restrictionIDs);
37534
37535             for (i = 0; i < restrictionIDs.length; i++) {
37536               relation = graph.entity(restrictionIDs[i]);
37537               if (!relation.isComplete(graph)) continue;
37538               var memberWays = relation.members.filter(function (m) {
37539                 return m.type === 'way';
37540               }).map(function (m) {
37541                 return graph.entity(m.id);
37542               });
37543               memberWays = utilArrayUniq(memberWays);
37544               var f = relation.memberByRole('from');
37545               var t = relation.memberByRole('to');
37546               var isUturn = f.id === t.id; // 2a. disable if connection would damage a restriction
37547               // (a key node is a node at the junction of ways)
37548
37549               var nodes = {
37550                 from: [],
37551                 via: [],
37552                 to: [],
37553                 keyfrom: [],
37554                 keyto: []
37555               };
37556
37557               for (j = 0; j < relation.members.length; j++) {
37558                 collectNodes(relation.members[j], nodes);
37559               }
37560
37561               nodes.keyfrom = utilArrayUniq(nodes.keyfrom.filter(hasDuplicates));
37562               nodes.keyto = utilArrayUniq(nodes.keyto.filter(hasDuplicates));
37563               var filter = keyNodeFilter(nodes.keyfrom, nodes.keyto);
37564               nodes.from = nodes.from.filter(filter);
37565               nodes.via = nodes.via.filter(filter);
37566               nodes.to = nodes.to.filter(filter);
37567               var connectFrom = false;
37568               var connectVia = false;
37569               var connectTo = false;
37570               var connectKeyFrom = false;
37571               var connectKeyTo = false;
37572
37573               for (j = 0; j < nodeIDs.length; j++) {
37574                 var n = nodeIDs[j];
37575
37576                 if (nodes.from.indexOf(n) !== -1) {
37577                   connectFrom = true;
37578                 }
37579
37580                 if (nodes.via.indexOf(n) !== -1) {
37581                   connectVia = true;
37582                 }
37583
37584                 if (nodes.to.indexOf(n) !== -1) {
37585                   connectTo = true;
37586                 }
37587
37588                 if (nodes.keyfrom.indexOf(n) !== -1) {
37589                   connectKeyFrom = true;
37590                 }
37591
37592                 if (nodes.keyto.indexOf(n) !== -1) {
37593                   connectKeyTo = true;
37594                 }
37595               }
37596
37597               if (connectFrom && connectTo && !isUturn) {
37598                 return 'restriction';
37599               }
37600
37601               if (connectFrom && connectVia) {
37602                 return 'restriction';
37603               }
37604
37605               if (connectTo && connectVia) {
37606                 return 'restriction';
37607               } // connecting to a key node -
37608               // if both nodes are on a member way (i.e. part of the turn restriction),
37609               // the connecting node must be adjacent to the key node.
37610
37611
37612               if (connectKeyFrom || connectKeyTo) {
37613                 if (nodeIDs.length !== 2) {
37614                   return 'restriction';
37615                 }
37616
37617                 var n0 = null;
37618                 var n1 = null;
37619
37620                 for (j = 0; j < memberWays.length; j++) {
37621                   way = memberWays[j];
37622
37623                   if (way.contains(nodeIDs[0])) {
37624                     n0 = nodeIDs[0];
37625                   }
37626
37627                   if (way.contains(nodeIDs[1])) {
37628                     n1 = nodeIDs[1];
37629                   }
37630                 }
37631
37632                 if (n0 && n1) {
37633                   // both nodes are part of the restriction
37634                   var ok = false;
37635
37636                   for (j = 0; j < memberWays.length; j++) {
37637                     way = memberWays[j];
37638
37639                     if (way.areAdjacent(n0, n1)) {
37640                       ok = true;
37641                       break;
37642                     }
37643                   }
37644
37645                   if (!ok) {
37646                     return 'restriction';
37647                   }
37648                 }
37649               } // 2b. disable if nodes being connected will destroy a member way in a restriction
37650               // (to test, make a copy and try actually connecting the nodes)
37651
37652
37653               for (j = 0; j < memberWays.length; j++) {
37654                 way = memberWays[j].update({}); // make copy
37655
37656                 for (k = 0; k < nodeIDs.length; k++) {
37657                   if (nodeIDs[k] === survivor.id) continue;
37658
37659                   if (way.areAdjacent(nodeIDs[k], survivor.id)) {
37660                     way = way.removeNode(nodeIDs[k]);
37661                   } else {
37662                     way = way.replaceNode(nodeIDs[k], survivor.id);
37663                   }
37664                 }
37665
37666                 if (way.isDegenerate()) {
37667                   return 'restriction';
37668                 }
37669               }
37670             }
37671
37672             return false; // if a key node appears multiple times (indexOf !== lastIndexOf) it's a FROM-VIA or TO-VIA junction
37673
37674             function hasDuplicates(n, i, arr) {
37675               return arr.indexOf(n) !== arr.lastIndexOf(n);
37676             }
37677
37678             function keyNodeFilter(froms, tos) {
37679               return function (n) {
37680                 return froms.indexOf(n) === -1 && tos.indexOf(n) === -1;
37681               };
37682             }
37683
37684             function collectNodes(member, collection) {
37685               var entity = graph.hasEntity(member.id);
37686               if (!entity) return;
37687               var role = member.role || '';
37688
37689               if (!collection[role]) {
37690                 collection[role] = [];
37691               }
37692
37693               if (member.type === 'node') {
37694                 collection[role].push(member.id);
37695
37696                 if (role === 'via') {
37697                   collection.keyfrom.push(member.id);
37698                   collection.keyto.push(member.id);
37699                 }
37700               } else if (member.type === 'way') {
37701                 collection[role].push.apply(collection[role], entity.nodes);
37702
37703                 if (role === 'from' || role === 'via') {
37704                   collection.keyfrom.push(entity.first());
37705                   collection.keyfrom.push(entity.last());
37706                 }
37707
37708                 if (role === 'to' || role === 'via') {
37709                   collection.keyto.push(entity.first());
37710                   collection.keyto.push(entity.last());
37711                 }
37712               }
37713             }
37714           };
37715
37716           return action;
37717         }
37718
37719         function actionCopyEntities(ids, fromGraph) {
37720           var _copies = {};
37721
37722           var action = function action(graph) {
37723             ids.forEach(function (id) {
37724               fromGraph.entity(id).copy(fromGraph, _copies);
37725             });
37726
37727             for (var id in _copies) {
37728               graph = graph.replace(_copies[id]);
37729             }
37730
37731             return graph;
37732           };
37733
37734           action.copies = function () {
37735             return _copies;
37736           };
37737
37738           return action;
37739         }
37740
37741         function actionDeleteMember(relationId, memberIndex) {
37742           return function (graph) {
37743             var relation = graph.entity(relationId).removeMember(memberIndex);
37744             graph = graph.replace(relation);
37745
37746             if (relation.isDegenerate()) {
37747               graph = actionDeleteRelation(relation.id)(graph);
37748             }
37749
37750             return graph;
37751           };
37752         }
37753
37754         function actionDiscardTags(difference, discardTags) {
37755           discardTags = discardTags || {};
37756           return function (graph) {
37757             difference.modified().forEach(checkTags);
37758             difference.created().forEach(checkTags);
37759             return graph;
37760
37761             function checkTags(entity) {
37762               var keys = Object.keys(entity.tags);
37763               var didDiscard = false;
37764               var tags = {};
37765
37766               for (var i = 0; i < keys.length; i++) {
37767                 var k = keys[i];
37768
37769                 if (discardTags[k] || !entity.tags[k]) {
37770                   didDiscard = true;
37771                 } else {
37772                   tags[k] = entity.tags[k];
37773                 }
37774               }
37775
37776               if (didDiscard) {
37777                 graph = graph.replace(entity.update({
37778                   tags: tags
37779                 }));
37780               }
37781             }
37782           };
37783         }
37784
37785         //
37786         // Optionally, disconnect only the given ways.
37787         //
37788         // For testing convenience, accepts an ID to assign to the (first) new node.
37789         // Normally, this will be undefined and the way will automatically
37790         // be assigned a new ID.
37791         //
37792         // This is the inverse of `iD.actionConnect`.
37793         //
37794         // Reference:
37795         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
37796         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
37797         //
37798
37799         function actionDisconnect(nodeId, newNodeId) {
37800           var wayIds;
37801
37802           var action = function action(graph) {
37803             var node = graph.entity(nodeId);
37804             var connections = action.connections(graph);
37805             connections.forEach(function (connection) {
37806               var way = graph.entity(connection.wayID);
37807               var newNode = osmNode({
37808                 id: newNodeId,
37809                 loc: node.loc,
37810                 tags: node.tags
37811               });
37812               graph = graph.replace(newNode);
37813
37814               if (connection.index === 0 && way.isArea()) {
37815                 // replace shared node with shared node..
37816                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
37817               } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
37818                 // replace closing node with new new node..
37819                 graph = graph.replace(way.unclose().addNode(newNode.id));
37820               } else {
37821                 // replace shared node with multiple new nodes..
37822                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
37823               }
37824             });
37825             return graph;
37826           };
37827
37828           action.connections = function (graph) {
37829             var candidates = [];
37830             var keeping = false;
37831             var parentWays = graph.parentWays(graph.entity(nodeId));
37832             var way, waynode;
37833
37834             for (var i = 0; i < parentWays.length; i++) {
37835               way = parentWays[i];
37836
37837               if (wayIds && wayIds.indexOf(way.id) === -1) {
37838                 keeping = true;
37839                 continue;
37840               }
37841
37842               if (way.isArea() && way.nodes[0] === nodeId) {
37843                 candidates.push({
37844                   wayID: way.id,
37845                   index: 0
37846                 });
37847               } else {
37848                 for (var j = 0; j < way.nodes.length; j++) {
37849                   waynode = way.nodes[j];
37850
37851                   if (waynode === nodeId) {
37852                     if (way.isClosed() && parentWays.length > 1 && wayIds && wayIds.indexOf(way.id) !== -1 && j === way.nodes.length - 1) {
37853                       continue;
37854                     }
37855
37856                     candidates.push({
37857                       wayID: way.id,
37858                       index: j
37859                     });
37860                   }
37861                 }
37862               }
37863             }
37864
37865             return keeping ? candidates : candidates.slice(1);
37866           };
37867
37868           action.disabled = function (graph) {
37869             var connections = action.connections(graph);
37870             if (connections.length === 0) return 'not_connected';
37871             var parentWays = graph.parentWays(graph.entity(nodeId));
37872             var seenRelationIds = {};
37873             var sharedRelation;
37874             parentWays.forEach(function (way) {
37875               var relations = graph.parentRelations(way);
37876               relations.forEach(function (relation) {
37877                 if (relation.id in seenRelationIds) {
37878                   if (wayIds) {
37879                     if (wayIds.indexOf(way.id) !== -1 || wayIds.indexOf(seenRelationIds[relation.id]) !== -1) {
37880                       sharedRelation = relation;
37881                     }
37882                   } else {
37883                     sharedRelation = relation;
37884                   }
37885                 } else {
37886                   seenRelationIds[relation.id] = way.id;
37887                 }
37888               });
37889             });
37890             if (sharedRelation) return 'relation';
37891           };
37892
37893           action.limitWays = function (val) {
37894             if (!arguments.length) return wayIds;
37895             wayIds = val;
37896             return action;
37897           };
37898
37899           return action;
37900         }
37901
37902         function actionExtract(entityID, projection) {
37903           var extractedNodeID;
37904
37905           var action = function action(graph) {
37906             var entity = graph.entity(entityID);
37907
37908             if (entity.type === 'node') {
37909               return extractFromNode(entity, graph);
37910             }
37911
37912             return extractFromWayOrRelation(entity, graph);
37913           };
37914
37915           function extractFromNode(node, graph) {
37916             extractedNodeID = node.id; // Create a new node to replace the one we will detach
37917
37918             var replacement = osmNode({
37919               loc: node.loc
37920             });
37921             graph = graph.replace(replacement); // Process each way in turn, updating the graph as we go
37922
37923             graph = graph.parentWays(node).reduce(function (accGraph, parentWay) {
37924               return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
37925             }, graph); // Process any relations too
37926
37927             return graph.parentRelations(node).reduce(function (accGraph, parentRel) {
37928               return accGraph.replace(parentRel.replaceMember(node, replacement));
37929             }, graph);
37930           }
37931
37932           function extractFromWayOrRelation(entity, graph) {
37933             var fromGeometry = entity.geometry(graph);
37934             var keysToCopyAndRetain = ['source', 'wheelchair'];
37935             var keysToRetain = ['area'];
37936             var buildingKeysToRetain = ['architect', 'building', 'height', 'layer'];
37937             var extractedLoc = d3_geoPath(projection).centroid(entity.asGeoJSON(graph));
37938             extractedLoc = extractedLoc && projection.invert(extractedLoc);
37939
37940             if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
37941               extractedLoc = entity.extent(graph).center();
37942             }
37943
37944             var indoorAreaValues = {
37945               area: true,
37946               corridor: true,
37947               elevator: true,
37948               level: true,
37949               room: true
37950             };
37951             var isBuilding = entity.tags.building && entity.tags.building !== 'no' || entity.tags['building:part'] && entity.tags['building:part'] !== 'no';
37952             var isIndoorArea = fromGeometry === 'area' && entity.tags.indoor && indoorAreaValues[entity.tags.indoor];
37953             var entityTags = Object.assign({}, entity.tags); // shallow copy
37954
37955             var pointTags = {};
37956
37957             for (var key in entityTags) {
37958               if (entity.type === 'relation' && key === 'type') {
37959                 continue;
37960               }
37961
37962               if (keysToRetain.indexOf(key) !== -1) {
37963                 continue;
37964               }
37965
37966               if (isBuilding) {
37967                 // don't transfer building-related tags
37968                 if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
37969               } // leave `indoor` tag on the area
37970
37971
37972               if (isIndoorArea && key === 'indoor') {
37973                 continue;
37974               } // copy the tag from the entity to the point
37975
37976
37977               pointTags[key] = entityTags[key]; // leave addresses and some other tags so they're on both features
37978
37979               if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
37980                 continue;
37981               } else if (isIndoorArea && key === 'level') {
37982                 // leave `level` on both features
37983                 continue;
37984               } // remove the tag from the entity
37985
37986
37987               delete entityTags[key];
37988             }
37989
37990             if (!isBuilding && !isIndoorArea && fromGeometry === 'area') {
37991               // ensure that areas keep area geometry
37992               entityTags.area = 'yes';
37993             }
37994
37995             var replacement = osmNode({
37996               loc: extractedLoc,
37997               tags: pointTags
37998             });
37999             graph = graph.replace(replacement);
38000             extractedNodeID = replacement.id;
38001             return graph.replace(entity.update({
38002               tags: entityTags
38003             }));
38004           }
38005
38006           action.getExtractedNodeID = function () {
38007             return extractedNodeID;
38008           };
38009
38010           return action;
38011         }
38012
38013         //
38014         // This is the inverse of `iD.actionSplit`.
38015         //
38016         // Reference:
38017         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
38018         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
38019         //
38020
38021         function actionJoin(ids) {
38022           function groupEntitiesByGeometry(graph) {
38023             var entities = ids.map(function (id) {
38024               return graph.entity(id);
38025             });
38026             return Object.assign({
38027               line: []
38028             }, utilArrayGroupBy(entities, function (entity) {
38029               return entity.geometry(graph);
38030             }));
38031           }
38032
38033           var action = function action(graph) {
38034             var ways = ids.map(graph.entity, graph);
38035             var survivorID = ways[0].id; // if any of the ways are sided (e.g. coastline, cliff, kerb)
38036             // sort them first so they establish the overall order - #6033
38037
38038             ways.sort(function (a, b) {
38039               var aSided = a.isSided();
38040               var bSided = b.isSided();
38041               return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
38042             }); // Prefer to keep an existing way.
38043
38044             for (var i = 0; i < ways.length; i++) {
38045               if (!ways[i].isNew()) {
38046                 survivorID = ways[i].id;
38047                 break;
38048               }
38049             }
38050
38051             var sequences = osmJoinWays(ways, graph);
38052             var joined = sequences[0]; // We might need to reverse some of these ways before joining them.  #4688
38053             // `joined.actions` property will contain any actions we need to apply.
38054
38055             graph = sequences.actions.reduce(function (g, action) {
38056               return action(g);
38057             }, graph);
38058             var survivor = graph.entity(survivorID);
38059             survivor = survivor.update({
38060               nodes: joined.nodes.map(function (n) {
38061                 return n.id;
38062               })
38063             });
38064             graph = graph.replace(survivor);
38065             joined.forEach(function (way) {
38066               if (way.id === survivorID) return;
38067               graph.parentRelations(way).forEach(function (parent) {
38068                 graph = graph.replace(parent.replaceMember(way, survivor));
38069               });
38070               survivor = survivor.mergeTags(way.tags);
38071               graph = graph.replace(survivor);
38072               graph = actionDeleteWay(way.id)(graph);
38073             }); // Finds if the join created a single-member multipolygon,
38074             // and if so turns it into a basic area instead
38075
38076             function checkForSimpleMultipolygon() {
38077               if (!survivor.isClosed()) return;
38078               var multipolygons = graph.parentMultipolygons(survivor).filter(function (multipolygon) {
38079                 // find multipolygons where the survivor is the only member
38080                 return multipolygon.members.length === 1;
38081               }); // skip if this is the single member of multiple multipolygons
38082
38083               if (multipolygons.length !== 1) return;
38084               var multipolygon = multipolygons[0];
38085
38086               for (var key in survivor.tags) {
38087                 if (multipolygon.tags[key] && // don't collapse if tags cannot be cleanly merged
38088                 multipolygon.tags[key] !== survivor.tags[key]) return;
38089               }
38090
38091               survivor = survivor.mergeTags(multipolygon.tags);
38092               graph = graph.replace(survivor);
38093               graph = actionDeleteRelation(multipolygon.id, true
38094               /* allow untagged members */
38095               )(graph);
38096               var tags = Object.assign({}, survivor.tags);
38097
38098               if (survivor.geometry(graph) !== 'area') {
38099                 // ensure the feature persists as an area
38100                 tags.area = 'yes';
38101               }
38102
38103               delete tags.type; // remove type=multipolygon
38104
38105               survivor = survivor.update({
38106                 tags: tags
38107               });
38108               graph = graph.replace(survivor);
38109             }
38110
38111             checkForSimpleMultipolygon();
38112             return graph;
38113           }; // Returns the number of nodes the resultant way is expected to have
38114
38115
38116           action.resultingWayNodesLength = function (graph) {
38117             return ids.reduce(function (count, id) {
38118               return count + graph.entity(id).nodes.length;
38119             }, 0) - ids.length - 1;
38120           };
38121
38122           action.disabled = function (graph) {
38123             var geometries = groupEntitiesByGeometry(graph);
38124
38125             if (ids.length < 2 || ids.length !== geometries.line.length) {
38126               return 'not_eligible';
38127             }
38128
38129             var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
38130
38131             if (joined.length > 1) {
38132               return 'not_adjacent';
38133             } // Loop through all combinations of path-pairs
38134             // to check potential intersections between all pairs
38135
38136
38137             for (var i = 0; i < ids.length - 1; i++) {
38138               for (var j = i + 1; j < ids.length; j++) {
38139                 var path1 = graph.childNodes(graph.entity(ids[i])).map(function (e) {
38140                   return e.loc;
38141                 });
38142                 var path2 = graph.childNodes(graph.entity(ids[j])).map(function (e) {
38143                   return e.loc;
38144                 });
38145                 var intersections = geoPathIntersections(path1, path2); // Check if intersections are just nodes lying on top of
38146                 // each other/the line, as opposed to crossing it
38147
38148                 var common = utilArrayIntersection(joined[0].nodes.map(function (n) {
38149                   return n.loc.toString();
38150                 }), intersections.map(function (n) {
38151                   return n.toString();
38152                 }));
38153
38154                 if (common.length !== intersections.length) {
38155                   return 'paths_intersect';
38156                 }
38157               }
38158             }
38159
38160             var nodeIds = joined[0].nodes.map(function (n) {
38161               return n.id;
38162             }).slice(1, -1);
38163             var relation;
38164             var tags = {};
38165             var conflicting = false;
38166             joined[0].forEach(function (way) {
38167               var parents = graph.parentRelations(way);
38168               parents.forEach(function (parent) {
38169                 if (parent.isRestriction() && parent.members.some(function (m) {
38170                   return nodeIds.indexOf(m.id) >= 0;
38171                 })) {
38172                   relation = parent;
38173                 }
38174               });
38175
38176               for (var k in way.tags) {
38177                 if (!(k in tags)) {
38178                   tags[k] = way.tags[k];
38179                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
38180                   conflicting = true;
38181                 }
38182               }
38183             });
38184
38185             if (relation) {
38186               return 'restriction';
38187             }
38188
38189             if (conflicting) {
38190               return 'conflicting_tags';
38191             }
38192           };
38193
38194           return action;
38195         }
38196
38197         function actionMerge(ids) {
38198           function groupEntitiesByGeometry(graph) {
38199             var entities = ids.map(function (id) {
38200               return graph.entity(id);
38201             });
38202             return Object.assign({
38203               point: [],
38204               area: [],
38205               line: [],
38206               relation: []
38207             }, utilArrayGroupBy(entities, function (entity) {
38208               return entity.geometry(graph);
38209             }));
38210           }
38211
38212           var action = function action(graph) {
38213             var geometries = groupEntitiesByGeometry(graph);
38214             var target = geometries.area[0] || geometries.line[0];
38215             var points = geometries.point;
38216             points.forEach(function (point) {
38217               target = target.mergeTags(point.tags);
38218               graph = graph.replace(target);
38219               graph.parentRelations(point).forEach(function (parent) {
38220                 graph = graph.replace(parent.replaceMember(point, target));
38221               });
38222               var nodes = utilArrayUniq(graph.childNodes(target));
38223               var removeNode = point;
38224
38225               for (var i = 0; i < nodes.length; i++) {
38226                 var node = nodes[i];
38227
38228                 if (graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags()) {
38229                   continue;
38230                 } // Found an uninteresting child node on the target way.
38231                 // Move orig point into its place to preserve point's history. #3683
38232
38233
38234                 graph = graph.replace(point.update({
38235                   tags: {},
38236                   loc: node.loc
38237                 }));
38238                 target = target.replaceNode(node.id, point.id);
38239                 graph = graph.replace(target);
38240                 removeNode = node;
38241                 break;
38242               }
38243
38244               graph = graph.remove(removeNode);
38245             });
38246
38247             if (target.tags.area === 'yes') {
38248               var tags = Object.assign({}, target.tags); // shallow copy
38249
38250               delete tags.area;
38251
38252               if (osmTagSuggestingArea(tags)) {
38253                 // remove the `area` tag if area geometry is now implied - #3851
38254                 target = target.update({
38255                   tags: tags
38256                 });
38257                 graph = graph.replace(target);
38258               }
38259             }
38260
38261             return graph;
38262           };
38263
38264           action.disabled = function (graph) {
38265             var geometries = groupEntitiesByGeometry(graph);
38266
38267             if (geometries.point.length === 0 || geometries.area.length + geometries.line.length !== 1 || geometries.relation.length !== 0) {
38268               return 'not_eligible';
38269             }
38270           };
38271
38272           return action;
38273         }
38274
38275         //
38276         // 1. move all the nodes to a common location
38277         // 2. `actionConnect` them
38278
38279         function actionMergeNodes(nodeIDs, loc) {
38280           // If there is a single "interesting" node, use that as the location.
38281           // Otherwise return the average location of all the nodes.
38282           function chooseLoc(graph) {
38283             if (!nodeIDs.length) return null;
38284             var sum = [0, 0];
38285             var interestingCount = 0;
38286             var interestingLoc;
38287
38288             for (var i = 0; i < nodeIDs.length; i++) {
38289               var node = graph.entity(nodeIDs[i]);
38290
38291               if (node.hasInterestingTags()) {
38292                 interestingLoc = ++interestingCount === 1 ? node.loc : null;
38293               }
38294
38295               sum = geoVecAdd(sum, node.loc);
38296             }
38297
38298             return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
38299           }
38300
38301           var action = function action(graph) {
38302             if (nodeIDs.length < 2) return graph;
38303             var toLoc = loc;
38304
38305             if (!toLoc) {
38306               toLoc = chooseLoc(graph);
38307             }
38308
38309             for (var i = 0; i < nodeIDs.length; i++) {
38310               var node = graph.entity(nodeIDs[i]);
38311
38312               if (node.loc !== toLoc) {
38313                 graph = graph.replace(node.move(toLoc));
38314               }
38315             }
38316
38317             return actionConnect(nodeIDs)(graph);
38318           };
38319
38320           action.disabled = function (graph) {
38321             if (nodeIDs.length < 2) return 'not_eligible';
38322
38323             for (var i = 0; i < nodeIDs.length; i++) {
38324               var entity = graph.entity(nodeIDs[i]);
38325               if (entity.type !== 'node') return 'not_eligible';
38326             }
38327
38328             return actionConnect(nodeIDs).disabled(graph);
38329           };
38330
38331           return action;
38332         }
38333
38334         function osmChangeset() {
38335           if (!(this instanceof osmChangeset)) {
38336             return new osmChangeset().initialize(arguments);
38337           } else if (arguments.length) {
38338             this.initialize(arguments);
38339           }
38340         }
38341         osmEntity.changeset = osmChangeset;
38342         osmChangeset.prototype = Object.create(osmEntity.prototype);
38343         Object.assign(osmChangeset.prototype, {
38344           type: 'changeset',
38345           extent: function extent() {
38346             return new geoExtent();
38347           },
38348           geometry: function geometry() {
38349             return 'changeset';
38350           },
38351           asJXON: function asJXON() {
38352             return {
38353               osm: {
38354                 changeset: {
38355                   tag: Object.keys(this.tags).map(function (k) {
38356                     return {
38357                       '@k': k,
38358                       '@v': this.tags[k]
38359                     };
38360                   }, this),
38361                   '@version': 0.6,
38362                   '@generator': 'iD'
38363                 }
38364               }
38365             };
38366           },
38367           // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
38368           // XML. Returns a string.
38369           osmChangeJXON: function osmChangeJXON(changes) {
38370             var changeset_id = this.id;
38371
38372             function nest(x, order) {
38373               var groups = {};
38374
38375               for (var i = 0; i < x.length; i++) {
38376                 var tagName = Object.keys(x[i])[0];
38377                 if (!groups[tagName]) groups[tagName] = [];
38378                 groups[tagName].push(x[i][tagName]);
38379               }
38380
38381               var ordered = {};
38382               order.forEach(function (o) {
38383                 if (groups[o]) ordered[o] = groups[o];
38384               });
38385               return ordered;
38386             } // sort relations in a changeset by dependencies
38387
38388
38389             function sort(changes) {
38390               // find a referenced relation in the current changeset
38391               function resolve(item) {
38392                 return relations.find(function (relation) {
38393                   return item.keyAttributes.type === 'relation' && item.keyAttributes.ref === relation['@id'];
38394                 });
38395               } // a new item is an item that has not been already processed
38396
38397
38398               function isNew(item) {
38399                 return !sorted[item['@id']] && !processing.find(function (proc) {
38400                   return proc['@id'] === item['@id'];
38401                 });
38402               }
38403
38404               var processing = [];
38405               var sorted = {};
38406               var relations = changes.relation;
38407               if (!relations) return changes;
38408
38409               for (var i = 0; i < relations.length; i++) {
38410                 var relation = relations[i]; // skip relation if already sorted
38411
38412                 if (!sorted[relation['@id']]) {
38413                   processing.push(relation);
38414                 }
38415
38416                 while (processing.length > 0) {
38417                   var next = processing[0],
38418                       deps = next.member.map(resolve).filter(Boolean).filter(isNew);
38419
38420                   if (deps.length === 0) {
38421                     sorted[next['@id']] = next;
38422                     processing.shift();
38423                   } else {
38424                     processing = deps.concat(processing);
38425                   }
38426                 }
38427               }
38428
38429               changes.relation = Object.values(sorted);
38430               return changes;
38431             }
38432
38433             function rep(entity) {
38434               return entity.asJXON(changeset_id);
38435             }
38436
38437             return {
38438               osmChange: {
38439                 '@version': 0.6,
38440                 '@generator': 'iD',
38441                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
38442                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
38443                 'delete': Object.assign(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {
38444                   '@if-unused': true
38445                 })
38446               }
38447             };
38448           },
38449           asGeoJSON: function asGeoJSON() {
38450             return {};
38451           }
38452         });
38453
38454         function osmNote() {
38455           if (!(this instanceof osmNote)) {
38456             return new osmNote().initialize(arguments);
38457           } else if (arguments.length) {
38458             this.initialize(arguments);
38459           }
38460         }
38461
38462         osmNote.id = function () {
38463           return osmNote.id.next--;
38464         };
38465
38466         osmNote.id.next = -1;
38467         Object.assign(osmNote.prototype, {
38468           type: 'note',
38469           initialize: function initialize(sources) {
38470             for (var i = 0; i < sources.length; ++i) {
38471               var source = sources[i];
38472
38473               for (var prop in source) {
38474                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
38475                   if (source[prop] === undefined) {
38476                     delete this[prop];
38477                   } else {
38478                     this[prop] = source[prop];
38479                   }
38480                 }
38481               }
38482             }
38483
38484             if (!this.id) {
38485               this.id = osmNote.id().toString();
38486             }
38487
38488             return this;
38489           },
38490           extent: function extent() {
38491             return new geoExtent(this.loc);
38492           },
38493           update: function update(attrs) {
38494             return osmNote(this, attrs); // {v: 1 + (this.v || 0)}
38495           },
38496           isNew: function isNew() {
38497             return this.id < 0;
38498           },
38499           move: function move(loc) {
38500             return this.update({
38501               loc: loc
38502             });
38503           }
38504         });
38505
38506         function osmRelation() {
38507           if (!(this instanceof osmRelation)) {
38508             return new osmRelation().initialize(arguments);
38509           } else if (arguments.length) {
38510             this.initialize(arguments);
38511           }
38512         }
38513         osmEntity.relation = osmRelation;
38514         osmRelation.prototype = Object.create(osmEntity.prototype);
38515
38516         osmRelation.creationOrder = function (a, b) {
38517           var aId = parseInt(osmEntity.id.toOSM(a.id), 10);
38518           var bId = parseInt(osmEntity.id.toOSM(b.id), 10);
38519           if (aId < 0 || bId < 0) return aId - bId;
38520           return bId - aId;
38521         };
38522
38523         Object.assign(osmRelation.prototype, {
38524           type: 'relation',
38525           members: [],
38526           copy: function copy(resolver, copies) {
38527             if (copies[this.id]) return copies[this.id];
38528             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
38529             var members = this.members.map(function (member) {
38530               return Object.assign({}, member, {
38531                 id: resolver.entity(member.id).copy(resolver, copies).id
38532               });
38533             });
38534             copy = copy.update({
38535               members: members
38536             });
38537             copies[this.id] = copy;
38538             return copy;
38539           },
38540           extent: function extent(resolver, memo) {
38541             return resolver["transient"](this, 'extent', function () {
38542               if (memo && memo[this.id]) return geoExtent();
38543               memo = memo || {};
38544               memo[this.id] = true;
38545               var extent = geoExtent();
38546
38547               for (var i = 0; i < this.members.length; i++) {
38548                 var member = resolver.hasEntity(this.members[i].id);
38549
38550                 if (member) {
38551                   extent._extend(member.extent(resolver, memo));
38552                 }
38553               }
38554
38555               return extent;
38556             });
38557           },
38558           geometry: function geometry(graph) {
38559             return graph["transient"](this, 'geometry', function () {
38560               return this.isMultipolygon() ? 'area' : 'relation';
38561             });
38562           },
38563           isDegenerate: function isDegenerate() {
38564             return this.members.length === 0;
38565           },
38566           // Return an array of members, each extended with an 'index' property whose value
38567           // is the member index.
38568           indexedMembers: function indexedMembers() {
38569             var result = new Array(this.members.length);
38570
38571             for (var i = 0; i < this.members.length; i++) {
38572               result[i] = Object.assign({}, this.members[i], {
38573                 index: i
38574               });
38575             }
38576
38577             return result;
38578           },
38579           // Return the first member with the given role. A copy of the member object
38580           // is returned, extended with an 'index' property whose value is the member index.
38581           memberByRole: function memberByRole(role) {
38582             for (var i = 0; i < this.members.length; i++) {
38583               if (this.members[i].role === role) {
38584                 return Object.assign({}, this.members[i], {
38585                   index: i
38586                 });
38587               }
38588             }
38589           },
38590           // Same as memberByRole, but returns all members with the given role
38591           membersByRole: function membersByRole(role) {
38592             var result = [];
38593
38594             for (var i = 0; i < this.members.length; i++) {
38595               if (this.members[i].role === role) {
38596                 result.push(Object.assign({}, this.members[i], {
38597                   index: i
38598                 }));
38599               }
38600             }
38601
38602             return result;
38603           },
38604           // Return the first member with the given id. A copy of the member object
38605           // is returned, extended with an 'index' property whose value is the member index.
38606           memberById: function memberById(id) {
38607             for (var i = 0; i < this.members.length; i++) {
38608               if (this.members[i].id === id) {
38609                 return Object.assign({}, this.members[i], {
38610                   index: i
38611                 });
38612               }
38613             }
38614           },
38615           // Return the first member with the given id and role. A copy of the member object
38616           // is returned, extended with an 'index' property whose value is the member index.
38617           memberByIdAndRole: function memberByIdAndRole(id, role) {
38618             for (var i = 0; i < this.members.length; i++) {
38619               if (this.members[i].id === id && this.members[i].role === role) {
38620                 return Object.assign({}, this.members[i], {
38621                   index: i
38622                 });
38623               }
38624             }
38625           },
38626           addMember: function addMember(member, index) {
38627             var members = this.members.slice();
38628             members.splice(index === undefined ? members.length : index, 0, member);
38629             return this.update({
38630               members: members
38631             });
38632           },
38633           updateMember: function updateMember(member, index) {
38634             var members = this.members.slice();
38635             members.splice(index, 1, Object.assign({}, members[index], member));
38636             return this.update({
38637               members: members
38638             });
38639           },
38640           removeMember: function removeMember(index) {
38641             var members = this.members.slice();
38642             members.splice(index, 1);
38643             return this.update({
38644               members: members
38645             });
38646           },
38647           removeMembersWithID: function removeMembersWithID(id) {
38648             var members = this.members.filter(function (m) {
38649               return m.id !== id;
38650             });
38651             return this.update({
38652               members: members
38653             });
38654           },
38655           moveMember: function moveMember(fromIndex, toIndex) {
38656             var members = this.members.slice();
38657             members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
38658             return this.update({
38659               members: members
38660             });
38661           },
38662           // Wherever a member appears with id `needle.id`, replace it with a member
38663           // with id `replacement.id`, type `replacement.type`, and the original role,
38664           // By default, adding a duplicate member (by id and role) is prevented.
38665           // Return an updated relation.
38666           replaceMember: function replaceMember(needle, replacement, keepDuplicates) {
38667             if (!this.memberById(needle.id)) return this;
38668             var members = [];
38669
38670             for (var i = 0; i < this.members.length; i++) {
38671               var member = this.members[i];
38672
38673               if (member.id !== needle.id) {
38674                 members.push(member);
38675               } else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
38676                 members.push({
38677                   id: replacement.id,
38678                   type: replacement.type,
38679                   role: member.role
38680                 });
38681               }
38682             }
38683
38684             return this.update({
38685               members: members
38686             });
38687           },
38688           asJXON: function asJXON(changeset_id) {
38689             var r = {
38690               relation: {
38691                 '@id': this.osmId(),
38692                 '@version': this.version || 0,
38693                 member: this.members.map(function (member) {
38694                   return {
38695                     keyAttributes: {
38696                       type: member.type,
38697                       role: member.role,
38698                       ref: osmEntity.id.toOSM(member.id)
38699                     }
38700                   };
38701                 }, this),
38702                 tag: Object.keys(this.tags).map(function (k) {
38703                   return {
38704                     keyAttributes: {
38705                       k: k,
38706                       v: this.tags[k]
38707                     }
38708                   };
38709                 }, this)
38710               }
38711             };
38712
38713             if (changeset_id) {
38714               r.relation['@changeset'] = changeset_id;
38715             }
38716
38717             return r;
38718           },
38719           asGeoJSON: function asGeoJSON(resolver) {
38720             return resolver["transient"](this, 'GeoJSON', function () {
38721               if (this.isMultipolygon()) {
38722                 return {
38723                   type: 'MultiPolygon',
38724                   coordinates: this.multipolygon(resolver)
38725                 };
38726               } else {
38727                 return {
38728                   type: 'FeatureCollection',
38729                   properties: this.tags,
38730                   features: this.members.map(function (member) {
38731                     return Object.assign({
38732                       role: member.role
38733                     }, resolver.entity(member.id).asGeoJSON(resolver));
38734                   })
38735                 };
38736               }
38737             });
38738           },
38739           area: function area(resolver) {
38740             return resolver["transient"](this, 'area', function () {
38741               return d3_geoArea(this.asGeoJSON(resolver));
38742             });
38743           },
38744           isMultipolygon: function isMultipolygon() {
38745             return this.tags.type === 'multipolygon';
38746           },
38747           isComplete: function isComplete(resolver) {
38748             for (var i = 0; i < this.members.length; i++) {
38749               if (!resolver.hasEntity(this.members[i].id)) {
38750                 return false;
38751               }
38752             }
38753
38754             return true;
38755           },
38756           hasFromViaTo: function hasFromViaTo() {
38757             return this.members.some(function (m) {
38758               return m.role === 'from';
38759             }) && this.members.some(function (m) {
38760               return m.role === 'via';
38761             }) && this.members.some(function (m) {
38762               return m.role === 'to';
38763             });
38764           },
38765           isRestriction: function isRestriction() {
38766             return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
38767           },
38768           isValidRestriction: function isValidRestriction() {
38769             if (!this.isRestriction()) return false;
38770             var froms = this.members.filter(function (m) {
38771               return m.role === 'from';
38772             });
38773             var vias = this.members.filter(function (m) {
38774               return m.role === 'via';
38775             });
38776             var tos = this.members.filter(function (m) {
38777               return m.role === 'to';
38778             });
38779             if (froms.length !== 1 && this.tags.restriction !== 'no_entry') return false;
38780             if (froms.some(function (m) {
38781               return m.type !== 'way';
38782             })) return false;
38783             if (tos.length !== 1 && this.tags.restriction !== 'no_exit') return false;
38784             if (tos.some(function (m) {
38785               return m.type !== 'way';
38786             })) return false;
38787             if (vias.length === 0) return false;
38788             if (vias.length > 1 && vias.some(function (m) {
38789               return m.type !== 'way';
38790             })) return false;
38791             return true;
38792           },
38793           // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
38794           // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
38795           //
38796           // This corresponds to the structure needed for rendering a multipolygon path using a
38797           // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
38798           //
38799           // In the case of invalid geometries, this function will still return a result which
38800           // includes the nodes of all way members, but some Nds may be unclosed and some inner
38801           // rings not matched with the intended outer ring.
38802           //
38803           multipolygon: function multipolygon(resolver) {
38804             var outers = this.members.filter(function (m) {
38805               return 'outer' === (m.role || 'outer');
38806             });
38807             var inners = this.members.filter(function (m) {
38808               return 'inner' === m.role;
38809             });
38810             outers = osmJoinWays(outers, resolver);
38811             inners = osmJoinWays(inners, resolver);
38812
38813             var sequenceToLineString = function sequenceToLineString(sequence) {
38814               if (sequence.nodes.length > 2 && sequence.nodes[0] !== sequence.nodes[sequence.nodes.length - 1]) {
38815                 // close unclosed parts to ensure correct area rendering - #2945
38816                 sequence.nodes.push(sequence.nodes[0]);
38817               }
38818
38819               return sequence.nodes.map(function (node) {
38820                 return node.loc;
38821               });
38822             };
38823
38824             outers = outers.map(sequenceToLineString);
38825             inners = inners.map(sequenceToLineString);
38826             var result = outers.map(function (o) {
38827               // Heuristic for detecting counterclockwise winding order. Assumes
38828               // that OpenStreetMap polygons are not hemisphere-spanning.
38829               return [d3_geoArea({
38830                 type: 'Polygon',
38831                 coordinates: [o]
38832               }) > 2 * Math.PI ? o.reverse() : o];
38833             });
38834
38835             function findOuter(inner) {
38836               var o, outer;
38837
38838               for (o = 0; o < outers.length; o++) {
38839                 outer = outers[o];
38840
38841                 if (geoPolygonContainsPolygon(outer, inner)) {
38842                   return o;
38843                 }
38844               }
38845
38846               for (o = 0; o < outers.length; o++) {
38847                 outer = outers[o];
38848
38849                 if (geoPolygonIntersectsPolygon(outer, inner, false)) {
38850                   return o;
38851                 }
38852               }
38853             }
38854
38855             for (var i = 0; i < inners.length; i++) {
38856               var inner = inners[i];
38857
38858               if (d3_geoArea({
38859                 type: 'Polygon',
38860                 coordinates: [inner]
38861               }) < 2 * Math.PI) {
38862                 inner = inner.reverse();
38863               }
38864
38865               var o = findOuter(inners[i]);
38866
38867               if (o !== undefined) {
38868                 result[o].push(inners[i]);
38869               } else {
38870                 result.push([inners[i]]); // Invalid geometry
38871               }
38872             }
38873
38874             return result;
38875           }
38876         });
38877
38878         var QAItem = /*#__PURE__*/function () {
38879           function QAItem(loc, service, itemType, id, props) {
38880             _classCallCheck$1(this, QAItem);
38881
38882             // Store required properties
38883             this.loc = loc;
38884             this.service = service.title;
38885             this.itemType = itemType; // All issues must have an ID for selection, use generic if none specified
38886
38887             this.id = id ? id : "".concat(QAItem.id());
38888             this.update(props); // Some QA services have marker icons to differentiate issues
38889
38890             if (service && typeof service.getIcon === 'function') {
38891               this.icon = service.getIcon(itemType);
38892             }
38893           }
38894
38895           _createClass$1(QAItem, [{
38896             key: "update",
38897             value: function update(props) {
38898               var _this = this;
38899
38900               // You can't override this initial information
38901               var loc = this.loc,
38902                   service = this.service,
38903                   itemType = this.itemType,
38904                   id = this.id;
38905               Object.keys(props).forEach(function (prop) {
38906                 return _this[prop] = props[prop];
38907               });
38908               this.loc = loc;
38909               this.service = service;
38910               this.itemType = itemType;
38911               this.id = id;
38912               return this;
38913             } // Generic handling for newly created QAItems
38914
38915           }], [{
38916             key: "id",
38917             value: function id() {
38918               return this.nextId--;
38919             }
38920           }]);
38921
38922           return QAItem;
38923         }();
38924         QAItem.nextId = -1;
38925
38926         //
38927         // Optionally, split only the given ways, if multiple ways share
38928         // the given node.
38929         //
38930         // This is the inverse of `iD.actionJoin`.
38931         //
38932         // For testing convenience, accepts an ID to assign to the new way.
38933         // Normally, this will be undefined and the way will automatically
38934         // be assigned a new ID.
38935         //
38936         // Reference:
38937         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
38938         //
38939
38940         function actionSplit(nodeIds, newWayIds) {
38941           // accept single ID for backwards-compatiblity
38942           if (typeof nodeIds === 'string') nodeIds = [nodeIds];
38943
38944           var _wayIDs; // the strategy for picking which way will have a new version and which way is newly created
38945
38946
38947           var _keepHistoryOn = 'longest'; // 'longest', 'first'
38948           // The IDs of the ways actually created by running this action
38949
38950           var _createdWayIDs = [];
38951
38952           function dist(graph, nA, nB) {
38953             var locA = graph.entity(nA).loc;
38954             var locB = graph.entity(nB).loc;
38955             var epsilon = 1e-6;
38956             return locA && locB ? geoSphericalDistance(locA, locB) : epsilon;
38957           } // If the way is closed, we need to search for a partner node
38958           // to split the way at.
38959           //
38960           // The following looks for a node that is both far away from
38961           // the initial node in terms of way segment length and nearby
38962           // in terms of beeline-distance. This assures that areas get
38963           // split on the most "natural" points (independent of the number
38964           // of nodes).
38965           // For example: bone-shaped areas get split across their waist
38966           // line, circles across the diameter.
38967
38968
38969           function splitArea(nodes, idxA, graph) {
38970             var lengths = new Array(nodes.length);
38971             var length;
38972             var i;
38973             var best = 0;
38974             var idxB;
38975
38976             function wrap(index) {
38977               return utilWrap(index, nodes.length);
38978             } // calculate lengths
38979
38980
38981             length = 0;
38982
38983             for (i = wrap(idxA + 1); i !== idxA; i = wrap(i + 1)) {
38984               length += dist(graph, nodes[i], nodes[wrap(i - 1)]);
38985               lengths[i] = length;
38986             }
38987
38988             length = 0;
38989
38990             for (i = wrap(idxA - 1); i !== idxA; i = wrap(i - 1)) {
38991               length += dist(graph, nodes[i], nodes[wrap(i + 1)]);
38992
38993               if (length < lengths[i]) {
38994                 lengths[i] = length;
38995               }
38996             } // determine best opposite node to split
38997
38998
38999             for (i = 0; i < nodes.length; i++) {
39000               var cost = lengths[i] / dist(graph, nodes[idxA], nodes[i]);
39001
39002               if (cost > best) {
39003                 idxB = i;
39004                 best = cost;
39005               }
39006             }
39007
39008             return idxB;
39009           }
39010
39011           function totalLengthBetweenNodes(graph, nodes) {
39012             var totalLength = 0;
39013
39014             for (var i = 0; i < nodes.length - 1; i++) {
39015               totalLength += dist(graph, nodes[i], nodes[i + 1]);
39016             }
39017
39018             return totalLength;
39019           }
39020
39021           function split(graph, nodeId, wayA, newWayId) {
39022             var wayB = osmWay({
39023               id: newWayId,
39024               tags: wayA.tags
39025             }); // `wayB` is the NEW way
39026
39027             var origNodes = wayA.nodes.slice();
39028             var nodesA;
39029             var nodesB;
39030             var isArea = wayA.isArea();
39031             var isOuter = osmIsOldMultipolygonOuterMember(wayA, graph);
39032
39033             if (wayA.isClosed()) {
39034               var nodes = wayA.nodes.slice(0, -1);
39035               var idxA = nodes.indexOf(nodeId);
39036               var idxB = splitArea(nodes, idxA, graph);
39037
39038               if (idxB < idxA) {
39039                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
39040                 nodesB = nodes.slice(idxB, idxA + 1);
39041               } else {
39042                 nodesA = nodes.slice(idxA, idxB + 1);
39043                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
39044               }
39045             } else {
39046               var idx = wayA.nodes.indexOf(nodeId, 1);
39047               nodesA = wayA.nodes.slice(0, idx + 1);
39048               nodesB = wayA.nodes.slice(idx);
39049             }
39050
39051             var lengthA = totalLengthBetweenNodes(graph, nodesA);
39052             var lengthB = totalLengthBetweenNodes(graph, nodesB);
39053
39054             if (_keepHistoryOn === 'longest' && lengthB > lengthA) {
39055               // keep the history on the longer way, regardless of the node count
39056               wayA = wayA.update({
39057                 nodes: nodesB
39058               });
39059               wayB = wayB.update({
39060                 nodes: nodesA
39061               });
39062               var temp = lengthA;
39063               lengthA = lengthB;
39064               lengthB = temp;
39065             } else {
39066               wayA = wayA.update({
39067                 nodes: nodesA
39068               });
39069               wayB = wayB.update({
39070                 nodes: nodesB
39071               });
39072             }
39073
39074             if (wayA.tags.step_count) {
39075               // divide up the the step count proportionally between the two ways
39076               var stepCount = parseFloat(wayA.tags.step_count);
39077
39078               if (stepCount && // ensure a number
39079               isFinite(stepCount) && // ensure positive
39080               stepCount > 0 && // ensure integer
39081               Math.round(stepCount) === stepCount) {
39082                 var tagsA = Object.assign({}, wayA.tags);
39083                 var tagsB = Object.assign({}, wayB.tags);
39084                 var ratioA = lengthA / (lengthA + lengthB);
39085                 var countA = Math.round(stepCount * ratioA);
39086                 tagsA.step_count = countA.toString();
39087                 tagsB.step_count = (stepCount - countA).toString();
39088                 wayA = wayA.update({
39089                   tags: tagsA
39090                 });
39091                 wayB = wayB.update({
39092                   tags: tagsB
39093                 });
39094               }
39095             }
39096
39097             graph = graph.replace(wayA);
39098             graph = graph.replace(wayB);
39099             graph.parentRelations(wayA).forEach(function (relation) {
39100               var member; // Turn restrictions - make sure:
39101               // 1. Splitting a FROM/TO way - only `wayA` OR `wayB` remains in relation
39102               //    (whichever one is connected to the VIA node/ways)
39103               // 2. Splitting a VIA way - `wayB` remains in relation as a VIA way
39104
39105               if (relation.hasFromViaTo()) {
39106                 var f = relation.memberByRole('from');
39107                 var v = relation.membersByRole('via');
39108                 var t = relation.memberByRole('to');
39109                 var i; // 1. split a FROM/TO
39110
39111                 if (f.id === wayA.id || t.id === wayA.id) {
39112                   var keepB = false;
39113
39114                   if (v.length === 1 && v[0].type === 'node') {
39115                     // check via node
39116                     keepB = wayB.contains(v[0].id);
39117                   } else {
39118                     // check via way(s)
39119                     for (i = 0; i < v.length; i++) {
39120                       if (v[i].type === 'way') {
39121                         var wayVia = graph.hasEntity(v[i].id);
39122
39123                         if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
39124                           keepB = true;
39125                           break;
39126                         }
39127                       }
39128                     }
39129                   }
39130
39131                   if (keepB) {
39132                     relation = relation.replaceMember(wayA, wayB);
39133                     graph = graph.replace(relation);
39134                   } // 2. split a VIA
39135
39136                 } else {
39137                   for (i = 0; i < v.length; i++) {
39138                     if (v[i].type === 'way' && v[i].id === wayA.id) {
39139                       member = {
39140                         id: wayB.id,
39141                         type: 'way',
39142                         role: 'via'
39143                       };
39144                       graph = actionAddMember(relation.id, member, v[i].index + 1)(graph);
39145                       break;
39146                     }
39147                   }
39148                 } // All other relations (Routes, Multipolygons, etc):
39149                 // 1. Both `wayA` and `wayB` remain in the relation
39150                 // 2. But must be inserted as a pair (see `actionAddMember` for details)
39151
39152               } else {
39153                 if (relation === isOuter) {
39154                   graph = graph.replace(relation.mergeTags(wayA.tags));
39155                   graph = graph.replace(wayA.update({
39156                     tags: {}
39157                   }));
39158                   graph = graph.replace(wayB.update({
39159                     tags: {}
39160                   }));
39161                 }
39162
39163                 member = {
39164                   id: wayB.id,
39165                   type: 'way',
39166                   role: relation.memberById(wayA.id).role
39167                 };
39168                 var insertPair = {
39169                   originalID: wayA.id,
39170                   insertedID: wayB.id,
39171                   nodes: origNodes
39172                 };
39173                 graph = actionAddMember(relation.id, member, undefined, insertPair)(graph);
39174               }
39175             });
39176
39177             if (!isOuter && isArea) {
39178               var multipolygon = osmRelation({
39179                 tags: Object.assign({}, wayA.tags, {
39180                   type: 'multipolygon'
39181                 }),
39182                 members: [{
39183                   id: wayA.id,
39184                   role: 'outer',
39185                   type: 'way'
39186                 }, {
39187                   id: wayB.id,
39188                   role: 'outer',
39189                   type: 'way'
39190                 }]
39191               });
39192               graph = graph.replace(multipolygon);
39193               graph = graph.replace(wayA.update({
39194                 tags: {}
39195               }));
39196               graph = graph.replace(wayB.update({
39197                 tags: {}
39198               }));
39199             }
39200
39201             _createdWayIDs.push(wayB.id);
39202
39203             return graph;
39204           }
39205
39206           var action = function action(graph) {
39207             _createdWayIDs = [];
39208             var newWayIndex = 0;
39209
39210             for (var i = 0; i < nodeIds.length; i++) {
39211               var nodeId = nodeIds[i];
39212               var candidates = action.waysForNode(nodeId, graph);
39213
39214               for (var j = 0; j < candidates.length; j++) {
39215                 graph = split(graph, nodeId, candidates[j], newWayIds && newWayIds[newWayIndex]);
39216                 newWayIndex += 1;
39217               }
39218             }
39219
39220             return graph;
39221           };
39222
39223           action.getCreatedWayIDs = function () {
39224             return _createdWayIDs;
39225           };
39226
39227           action.waysForNode = function (nodeId, graph) {
39228             var node = graph.entity(nodeId);
39229             var splittableParents = graph.parentWays(node).filter(isSplittable);
39230
39231             if (!_wayIDs) {
39232               // If the ways to split aren't specified, only split the lines.
39233               // If there are no lines to split, split the areas.
39234               var hasLine = splittableParents.some(function (parent) {
39235                 return parent.geometry(graph) === 'line';
39236               });
39237
39238               if (hasLine) {
39239                 return splittableParents.filter(function (parent) {
39240                   return parent.geometry(graph) === 'line';
39241                 });
39242               }
39243             }
39244
39245             return splittableParents;
39246
39247             function isSplittable(parent) {
39248               // If the ways to split are specified, ignore everything else.
39249               if (_wayIDs && _wayIDs.indexOf(parent.id) === -1) return false; // We can fake splitting closed ways at their endpoints...
39250
39251               if (parent.isClosed()) return true; // otherwise, we can't split nodes at their endpoints.
39252
39253               for (var i = 1; i < parent.nodes.length - 1; i++) {
39254                 if (parent.nodes[i] === nodeId) return true;
39255               }
39256
39257               return false;
39258             }
39259           };
39260
39261           action.ways = function (graph) {
39262             return utilArrayUniq([].concat.apply([], nodeIds.map(function (nodeId) {
39263               return action.waysForNode(nodeId, graph);
39264             })));
39265           };
39266
39267           action.disabled = function (graph) {
39268             for (var i = 0; i < nodeIds.length; i++) {
39269               var nodeId = nodeIds[i];
39270               var candidates = action.waysForNode(nodeId, graph);
39271
39272               if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
39273                 return 'not_eligible';
39274               }
39275             }
39276           };
39277
39278           action.limitWays = function (val) {
39279             if (!arguments.length) return _wayIDs;
39280             _wayIDs = val;
39281             return action;
39282           };
39283
39284           action.keepHistoryOn = function (val) {
39285             if (!arguments.length) return _keepHistoryOn;
39286             _keepHistoryOn = val;
39287             return action;
39288           };
39289
39290           return action;
39291         }
39292
39293         function coreGraph(other, mutable) {
39294           if (!(this instanceof coreGraph)) return new coreGraph(other, mutable);
39295
39296           if (other instanceof coreGraph) {
39297             var base = other.base();
39298             this.entities = Object.assign(Object.create(base.entities), other.entities);
39299             this._parentWays = Object.assign(Object.create(base.parentWays), other._parentWays);
39300             this._parentRels = Object.assign(Object.create(base.parentRels), other._parentRels);
39301           } else {
39302             this.entities = Object.create({});
39303             this._parentWays = Object.create({});
39304             this._parentRels = Object.create({});
39305             this.rebase(other || [], [this]);
39306           }
39307
39308           this.transients = {};
39309           this._childNodes = {};
39310           this.frozen = !mutable;
39311         }
39312         coreGraph.prototype = {
39313           hasEntity: function hasEntity(id) {
39314             return this.entities[id];
39315           },
39316           entity: function entity(id) {
39317             var entity = this.entities[id]; //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
39318
39319             if (!entity) {
39320               entity = this.entities.__proto__[id]; // eslint-disable-line no-proto
39321             }
39322
39323             if (!entity) {
39324               throw new Error('entity ' + id + ' not found');
39325             }
39326
39327             return entity;
39328           },
39329           geometry: function geometry(id) {
39330             return this.entity(id).geometry(this);
39331           },
39332           "transient": function transient(entity, key, fn) {
39333             var id = entity.id;
39334             var transients = this.transients[id] || (this.transients[id] = {});
39335
39336             if (transients[key] !== undefined) {
39337               return transients[key];
39338             }
39339
39340             transients[key] = fn.call(entity);
39341             return transients[key];
39342           },
39343           parentWays: function parentWays(entity) {
39344             var parents = this._parentWays[entity.id];
39345             var result = [];
39346
39347             if (parents) {
39348               parents.forEach(function (id) {
39349                 result.push(this.entity(id));
39350               }, this);
39351             }
39352
39353             return result;
39354           },
39355           isPoi: function isPoi(entity) {
39356             var parents = this._parentWays[entity.id];
39357             return !parents || parents.size === 0;
39358           },
39359           isShared: function isShared(entity) {
39360             var parents = this._parentWays[entity.id];
39361             return parents && parents.size > 1;
39362           },
39363           parentRelations: function parentRelations(entity) {
39364             var parents = this._parentRels[entity.id];
39365             var result = [];
39366
39367             if (parents) {
39368               parents.forEach(function (id) {
39369                 result.push(this.entity(id));
39370               }, this);
39371             }
39372
39373             return result;
39374           },
39375           parentMultipolygons: function parentMultipolygons(entity) {
39376             return this.parentRelations(entity).filter(function (relation) {
39377               return relation.isMultipolygon();
39378             });
39379           },
39380           childNodes: function childNodes(entity) {
39381             if (this._childNodes[entity.id]) return this._childNodes[entity.id];
39382             if (!entity.nodes) return [];
39383             var nodes = [];
39384
39385             for (var i = 0; i < entity.nodes.length; i++) {
39386               nodes[i] = this.entity(entity.nodes[i]);
39387             }
39388             this._childNodes[entity.id] = nodes;
39389             return this._childNodes[entity.id];
39390           },
39391           base: function base() {
39392             return {
39393               'entities': Object.getPrototypeOf(this.entities),
39394               'parentWays': Object.getPrototypeOf(this._parentWays),
39395               'parentRels': Object.getPrototypeOf(this._parentRels)
39396             };
39397           },
39398           // Unlike other graph methods, rebase mutates in place. This is because it
39399           // is used only during the history operation that merges newly downloaded
39400           // data into each state. To external consumers, it should appear as if the
39401           // graph always contained the newly downloaded data.
39402           rebase: function rebase(entities, stack, force) {
39403             var base = this.base();
39404             var i, j, k, id;
39405
39406             for (i = 0; i < entities.length; i++) {
39407               var entity = entities[i];
39408               if (!entity.visible || !force && base.entities[entity.id]) continue; // Merging data into the base graph
39409
39410               base.entities[entity.id] = entity;
39411
39412               this._updateCalculated(undefined, entity, base.parentWays, base.parentRels); // Restore provisionally-deleted nodes that are discovered to have an extant parent
39413
39414
39415               if (entity.type === 'way') {
39416                 for (j = 0; j < entity.nodes.length; j++) {
39417                   id = entity.nodes[j];
39418
39419                   for (k = 1; k < stack.length; k++) {
39420                     var ents = stack[k].entities;
39421
39422                     if (ents.hasOwnProperty(id) && ents[id] === undefined) {
39423                       delete ents[id];
39424                     }
39425                   }
39426                 }
39427               }
39428             }
39429
39430             for (i = 0; i < stack.length; i++) {
39431               stack[i]._updateRebased();
39432             }
39433           },
39434           _updateRebased: function _updateRebased() {
39435             var base = this.base();
39436             Object.keys(this._parentWays).forEach(function (child) {
39437               if (base.parentWays[child]) {
39438                 base.parentWays[child].forEach(function (id) {
39439                   if (!this.entities.hasOwnProperty(id)) {
39440                     this._parentWays[child].add(id);
39441                   }
39442                 }, this);
39443               }
39444             }, this);
39445             Object.keys(this._parentRels).forEach(function (child) {
39446               if (base.parentRels[child]) {
39447                 base.parentRels[child].forEach(function (id) {
39448                   if (!this.entities.hasOwnProperty(id)) {
39449                     this._parentRels[child].add(id);
39450                   }
39451                 }, this);
39452               }
39453             }, this);
39454             this.transients = {}; // this._childNodes is not updated, under the assumption that
39455             // ways are always downloaded with their child nodes.
39456           },
39457           // Updates calculated properties (parentWays, parentRels) for the specified change
39458           _updateCalculated: function _updateCalculated(oldentity, entity, parentWays, parentRels) {
39459             parentWays = parentWays || this._parentWays;
39460             parentRels = parentRels || this._parentRels;
39461             var type = entity && entity.type || oldentity && oldentity.type;
39462             var removed, added, i;
39463
39464             if (type === 'way') {
39465               // Update parentWays
39466               if (oldentity && entity) {
39467                 removed = utilArrayDifference(oldentity.nodes, entity.nodes);
39468                 added = utilArrayDifference(entity.nodes, oldentity.nodes);
39469               } else if (oldentity) {
39470                 removed = oldentity.nodes;
39471                 added = [];
39472               } else if (entity) {
39473                 removed = [];
39474                 added = entity.nodes;
39475               }
39476
39477               for (i = 0; i < removed.length; i++) {
39478                 // make a copy of prototype property, store as own property, and update..
39479                 parentWays[removed[i]] = new Set(parentWays[removed[i]]);
39480                 parentWays[removed[i]]["delete"](oldentity.id);
39481               }
39482
39483               for (i = 0; i < added.length; i++) {
39484                 // make a copy of prototype property, store as own property, and update..
39485                 parentWays[added[i]] = new Set(parentWays[added[i]]);
39486                 parentWays[added[i]].add(entity.id);
39487               }
39488             } else if (type === 'relation') {
39489               // Update parentRels
39490               // diff only on the IDs since the same entity can be a member multiple times with different roles
39491               var oldentityMemberIDs = oldentity ? oldentity.members.map(function (m) {
39492                 return m.id;
39493               }) : [];
39494               var entityMemberIDs = entity ? entity.members.map(function (m) {
39495                 return m.id;
39496               }) : [];
39497
39498               if (oldentity && entity) {
39499                 removed = utilArrayDifference(oldentityMemberIDs, entityMemberIDs);
39500                 added = utilArrayDifference(entityMemberIDs, oldentityMemberIDs);
39501               } else if (oldentity) {
39502                 removed = oldentityMemberIDs;
39503                 added = [];
39504               } else if (entity) {
39505                 removed = [];
39506                 added = entityMemberIDs;
39507               }
39508
39509               for (i = 0; i < removed.length; i++) {
39510                 // make a copy of prototype property, store as own property, and update..
39511                 parentRels[removed[i]] = new Set(parentRels[removed[i]]);
39512                 parentRels[removed[i]]["delete"](oldentity.id);
39513               }
39514
39515               for (i = 0; i < added.length; i++) {
39516                 // make a copy of prototype property, store as own property, and update..
39517                 parentRels[added[i]] = new Set(parentRels[added[i]]);
39518                 parentRels[added[i]].add(entity.id);
39519               }
39520             }
39521           },
39522           replace: function replace(entity) {
39523             if (this.entities[entity.id] === entity) return this;
39524             return this.update(function () {
39525               this._updateCalculated(this.entities[entity.id], entity);
39526
39527               this.entities[entity.id] = entity;
39528             });
39529           },
39530           remove: function remove(entity) {
39531             return this.update(function () {
39532               this._updateCalculated(entity, undefined);
39533
39534               this.entities[entity.id] = undefined;
39535             });
39536           },
39537           revert: function revert(id) {
39538             var baseEntity = this.base().entities[id];
39539             var headEntity = this.entities[id];
39540             if (headEntity === baseEntity) return this;
39541             return this.update(function () {
39542               this._updateCalculated(headEntity, baseEntity);
39543
39544               delete this.entities[id];
39545             });
39546           },
39547           update: function update() {
39548             var graph = this.frozen ? coreGraph(this, true) : this;
39549
39550             for (var i = 0; i < arguments.length; i++) {
39551               arguments[i].call(graph, graph);
39552             }
39553
39554             if (this.frozen) graph.frozen = true;
39555             return graph;
39556           },
39557           // Obliterates any existing entities
39558           load: function load(entities) {
39559             var base = this.base();
39560             this.entities = Object.create(base.entities);
39561
39562             for (var i in entities) {
39563               this.entities[i] = entities[i];
39564
39565               this._updateCalculated(base.entities[i], this.entities[i]);
39566             }
39567
39568             return this;
39569           }
39570         };
39571
39572         function osmTurn(turn) {
39573           if (!(this instanceof osmTurn)) {
39574             return new osmTurn(turn);
39575           }
39576
39577           Object.assign(this, turn);
39578         }
39579         function osmIntersection(graph, startVertexId, maxDistance) {
39580           maxDistance = maxDistance || 30; // in meters
39581
39582           var vgraph = coreGraph(); // virtual graph
39583
39584           var i, j, k;
39585
39586           function memberOfRestriction(entity) {
39587             return graph.parentRelations(entity).some(function (r) {
39588               return r.isRestriction();
39589             });
39590           }
39591
39592           function isRoad(way) {
39593             if (way.isArea() || way.isDegenerate()) return false;
39594             var roads = {
39595               'motorway': true,
39596               'motorway_link': true,
39597               'trunk': true,
39598               'trunk_link': true,
39599               'primary': true,
39600               'primary_link': true,
39601               'secondary': true,
39602               'secondary_link': true,
39603               'tertiary': true,
39604               'tertiary_link': true,
39605               'residential': true,
39606               'unclassified': true,
39607               'living_street': true,
39608               'service': true,
39609               'road': true,
39610               'track': true
39611             };
39612             return roads[way.tags.highway];
39613           }
39614
39615           var startNode = graph.entity(startVertexId);
39616           var checkVertices = [startNode];
39617           var checkWays;
39618           var vertices = [];
39619           var vertexIds = [];
39620           var vertex;
39621           var ways = [];
39622           var wayIds = [];
39623           var way;
39624           var nodes = [];
39625           var node;
39626           var parents = [];
39627           var parent; // `actions` will store whatever actions must be performed to satisfy
39628           // preconditions for adding a turn restriction to this intersection.
39629           //  - Remove any existing degenerate turn restrictions (missing from/to, etc)
39630           //  - Reverse oneways so that they are drawn in the forward direction
39631           //  - Split ways on key vertices
39632
39633           var actions = []; // STEP 1:  walk the graph outwards from starting vertex to search
39634           //  for more key vertices and ways to include in the intersection..
39635
39636           while (checkVertices.length) {
39637             vertex = checkVertices.pop(); // check this vertex for parent ways that are roads
39638
39639             checkWays = graph.parentWays(vertex);
39640             var hasWays = false;
39641
39642             for (i = 0; i < checkWays.length; i++) {
39643               way = checkWays[i];
39644               if (!isRoad(way) && !memberOfRestriction(way)) continue;
39645               ways.push(way); // it's a road, or it's already in a turn restriction
39646
39647               hasWays = true; // check the way's children for more key vertices
39648
39649               nodes = utilArrayUniq(graph.childNodes(way));
39650
39651               for (j = 0; j < nodes.length; j++) {
39652                 node = nodes[j];
39653                 if (node === vertex) continue; // same thing
39654
39655                 if (vertices.indexOf(node) !== -1) continue; // seen it already
39656
39657                 if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance) continue; // too far from start
39658                 // a key vertex will have parents that are also roads
39659
39660                 var hasParents = false;
39661                 parents = graph.parentWays(node);
39662
39663                 for (k = 0; k < parents.length; k++) {
39664                   parent = parents[k];
39665                   if (parent === way) continue; // same thing
39666
39667                   if (ways.indexOf(parent) !== -1) continue; // seen it already
39668
39669                   if (!isRoad(parent)) continue; // not a road
39670
39671                   hasParents = true;
39672                   break;
39673                 }
39674
39675                 if (hasParents) {
39676                   checkVertices.push(node);
39677                 }
39678               }
39679             }
39680
39681             if (hasWays) {
39682               vertices.push(vertex);
39683             }
39684           }
39685
39686           vertices = utilArrayUniq(vertices);
39687           ways = utilArrayUniq(ways); // STEP 2:  Build a virtual graph containing only the entities in the intersection..
39688           // Everything done after this step should act on the virtual graph
39689           // Any actions that must be performed later to the main graph go in `actions` array
39690
39691           ways.forEach(function (way) {
39692             graph.childNodes(way).forEach(function (node) {
39693               vgraph = vgraph.replace(node);
39694             });
39695             vgraph = vgraph.replace(way);
39696             graph.parentRelations(way).forEach(function (relation) {
39697               if (relation.isRestriction()) {
39698                 if (relation.isValidRestriction(graph)) {
39699                   vgraph = vgraph.replace(relation);
39700                 } else if (relation.isComplete(graph)) {
39701                   actions.push(actionDeleteRelation(relation.id));
39702                 }
39703               }
39704             });
39705           }); // STEP 3:  Force all oneways to be drawn in the forward direction
39706
39707           ways.forEach(function (w) {
39708             var way = vgraph.entity(w.id);
39709
39710             if (way.tags.oneway === '-1') {
39711               var action = actionReverse(way.id, {
39712                 reverseOneway: true
39713               });
39714               actions.push(action);
39715               vgraph = action(vgraph);
39716             }
39717           }); // STEP 4:  Split ways on key vertices
39718
39719           var origCount = osmEntity.id.next.way;
39720           vertices.forEach(function (v) {
39721             // This is an odd way to do it, but we need to find all the ways that
39722             // will be split here, then split them one at a time to ensure that these
39723             // actions can be replayed on the main graph exactly in the same order.
39724             // (It is unintuitive, but the order of ways returned from graph.parentWays()
39725             // is arbitrary, depending on how the main graph and vgraph were built)
39726             var splitAll = actionSplit([v.id]).keepHistoryOn('first');
39727
39728             if (!splitAll.disabled(vgraph)) {
39729               splitAll.ways(vgraph).forEach(function (way) {
39730                 var splitOne = actionSplit([v.id]).limitWays([way.id]).keepHistoryOn('first');
39731                 actions.push(splitOne);
39732                 vgraph = splitOne(vgraph);
39733               });
39734             }
39735           }); // In here is where we should also split the intersection at nearby junction.
39736           //   for https://github.com/mapbox/iD-internal/issues/31
39737           // nearbyVertices.forEach(function(v) {
39738           // });
39739           // Reasons why we reset the way id count here:
39740           //  1. Continuity with way ids created by the splits so that we can replay
39741           //     these actions later if the user decides to create a turn restriction
39742           //  2. Avoids churning way ids just by hovering over a vertex
39743           //     and displaying the turn restriction editor
39744
39745           osmEntity.id.next.way = origCount; // STEP 5:  Update arrays to point to vgraph entities
39746
39747           vertexIds = vertices.map(function (v) {
39748             return v.id;
39749           });
39750           vertices = [];
39751           ways = [];
39752           vertexIds.forEach(function (id) {
39753             var vertex = vgraph.entity(id);
39754             var parents = vgraph.parentWays(vertex);
39755             vertices.push(vertex);
39756             ways = ways.concat(parents);
39757           });
39758           vertices = utilArrayUniq(vertices);
39759           ways = utilArrayUniq(ways);
39760           vertexIds = vertices.map(function (v) {
39761             return v.id;
39762           });
39763           wayIds = ways.map(function (w) {
39764             return w.id;
39765           }); // STEP 6:  Update the ways with some metadata that will be useful for
39766           // walking the intersection graph later and rendering turn arrows.
39767
39768           function withMetadata(way, vertexIds) {
39769             var __oneWay = way.isOneWay(); // which affixes are key vertices?
39770
39771
39772             var __first = vertexIds.indexOf(way.first()) !== -1;
39773
39774             var __last = vertexIds.indexOf(way.last()) !== -1; // what roles is this way eligible for?
39775
39776
39777             var __via = __first && __last;
39778
39779             var __from = __first && !__oneWay || __last;
39780
39781             var __to = __first || __last && !__oneWay;
39782
39783             return way.update({
39784               __first: __first,
39785               __last: __last,
39786               __from: __from,
39787               __via: __via,
39788               __to: __to,
39789               __oneWay: __oneWay
39790             });
39791           }
39792
39793           ways = [];
39794           wayIds.forEach(function (id) {
39795             var way = withMetadata(vgraph.entity(id), vertexIds);
39796             vgraph = vgraph.replace(way);
39797             ways.push(way);
39798           }); // STEP 7:  Simplify - This is an iterative process where we:
39799           //  1. Find trivial vertices with only 2 parents
39800           //  2. trim off the leaf way from those vertices and remove from vgraph
39801
39802           var keepGoing;
39803           var removeWayIds = [];
39804           var removeVertexIds = [];
39805
39806           do {
39807             keepGoing = false;
39808             checkVertices = vertexIds.slice();
39809
39810             for (i = 0; i < checkVertices.length; i++) {
39811               var vertexId = checkVertices[i];
39812               vertex = vgraph.hasEntity(vertexId);
39813
39814               if (!vertex) {
39815                 if (vertexIds.indexOf(vertexId) !== -1) {
39816                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
39817                 }
39818
39819                 removeVertexIds.push(vertexId);
39820                 continue;
39821               }
39822
39823               parents = vgraph.parentWays(vertex);
39824
39825               if (parents.length < 3) {
39826                 if (vertexIds.indexOf(vertexId) !== -1) {
39827                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
39828                 }
39829               }
39830
39831               if (parents.length === 2) {
39832                 // vertex with 2 parents is trivial
39833                 var a = parents[0];
39834                 var b = parents[1];
39835                 var aIsLeaf = a && !a.__via;
39836                 var bIsLeaf = b && !b.__via;
39837                 var leaf, survivor;
39838
39839                 if (aIsLeaf && !bIsLeaf) {
39840                   leaf = a;
39841                   survivor = b;
39842                 } else if (!aIsLeaf && bIsLeaf) {
39843                   leaf = b;
39844                   survivor = a;
39845                 }
39846
39847                 if (leaf && survivor) {
39848                   survivor = withMetadata(survivor, vertexIds); // update survivor way
39849
39850                   vgraph = vgraph.replace(survivor).remove(leaf); // update graph
39851
39852                   removeWayIds.push(leaf.id);
39853                   keepGoing = true;
39854                 }
39855               }
39856
39857               parents = vgraph.parentWays(vertex);
39858
39859               if (parents.length < 2) {
39860                 // vertex is no longer a key vertex
39861                 if (vertexIds.indexOf(vertexId) !== -1) {
39862                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
39863                 }
39864
39865                 removeVertexIds.push(vertexId);
39866                 keepGoing = true;
39867               }
39868
39869               if (parents.length < 1) {
39870                 // vertex is no longer attached to anything
39871                 vgraph = vgraph.remove(vertex);
39872               }
39873             }
39874           } while (keepGoing);
39875
39876           vertices = vertices.filter(function (vertex) {
39877             return removeVertexIds.indexOf(vertex.id) === -1;
39878           }).map(function (vertex) {
39879             return vgraph.entity(vertex.id);
39880           });
39881           ways = ways.filter(function (way) {
39882             return removeWayIds.indexOf(way.id) === -1;
39883           }).map(function (way) {
39884             return vgraph.entity(way.id);
39885           }); // OK!  Here is our intersection..
39886
39887           var intersection = {
39888             graph: vgraph,
39889             actions: actions,
39890             vertices: vertices,
39891             ways: ways
39892           }; // Get all the valid turns through this intersection given a starting way id.
39893           // This operates on the virtual graph for everything.
39894           //
39895           // Basically, walk through all possible paths from starting way,
39896           //   honoring the existing turn restrictions as we go (watch out for loops!)
39897           //
39898           // For each path found, generate and return a `osmTurn` datastructure.
39899           //
39900
39901           intersection.turns = function (fromWayId, maxViaWay) {
39902             if (!fromWayId) return [];
39903             if (!maxViaWay) maxViaWay = 0;
39904             var vgraph = intersection.graph;
39905             var keyVertexIds = intersection.vertices.map(function (v) {
39906               return v.id;
39907             });
39908             var start = vgraph.entity(fromWayId);
39909             if (!start || !(start.__from || start.__via)) return []; // maxViaWay=0   from-*-to              (0 vias)
39910             // maxViaWay=1   from-*-via-*-to        (1 via max)
39911             // maxViaWay=2   from-*-via-*-via-*-to  (2 vias max)
39912
39913             var maxPathLength = maxViaWay * 2 + 3;
39914             var turns = [];
39915             step(start);
39916             return turns; // traverse the intersection graph and find all the valid paths
39917
39918             function step(entity, currPath, currRestrictions, matchedRestriction) {
39919               currPath = (currPath || []).slice(); // shallow copy
39920
39921               if (currPath.length >= maxPathLength) return;
39922               currPath.push(entity.id);
39923               currRestrictions = (currRestrictions || []).slice(); // shallow copy
39924
39925               var i, j;
39926
39927               if (entity.type === 'node') {
39928                 var parents = vgraph.parentWays(entity);
39929                 var nextWays = []; // which ways can we step into?
39930
39931                 for (i = 0; i < parents.length; i++) {
39932                   var way = parents[i]; // if next way is a oneway incoming to this vertex, skip
39933
39934                   if (way.__oneWay && way.nodes[0] !== entity.id) continue; // if we have seen it before (allowing for an initial u-turn), skip
39935
39936                   if (currPath.indexOf(way.id) !== -1 && currPath.length >= 3) continue; // Check all "current" restrictions (where we've already walked the `FROM`)
39937
39938                   var restrict = null;
39939
39940                   for (j = 0; j < currRestrictions.length; j++) {
39941                     var restriction = currRestrictions[j];
39942                     var f = restriction.memberByRole('from');
39943                     var v = restriction.membersByRole('via');
39944                     var t = restriction.memberByRole('to');
39945                     var isOnly = /^only_/.test(restriction.tags.restriction); // Does the current path match this turn restriction?
39946
39947                     var matchesFrom = f.id === fromWayId;
39948                     var matchesViaTo = false;
39949                     var isAlongOnlyPath = false;
39950
39951                     if (t.id === way.id) {
39952                       // match TO
39953                       if (v.length === 1 && v[0].type === 'node') {
39954                         // match VIA node
39955                         matchesViaTo = v[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
39956                       } else {
39957                         // match all VIA ways
39958                         var pathVias = [];
39959
39960                         for (k = 2; k < currPath.length; k += 2) {
39961                           // k = 2 skips FROM
39962                           pathVias.push(currPath[k]); // (path goes way-node-way...)
39963                         }
39964
39965                         var restrictionVias = [];
39966
39967                         for (k = 0; k < v.length; k++) {
39968                           if (v[k].type === 'way') {
39969                             restrictionVias.push(v[k].id);
39970                           }
39971                         }
39972
39973                         var diff = utilArrayDifference(pathVias, restrictionVias);
39974                         matchesViaTo = !diff.length;
39975                       }
39976                     } else if (isOnly) {
39977                       for (k = 0; k < v.length; k++) {
39978                         // way doesn't match TO, but is one of the via ways along the path of an "only"
39979                         if (v[k].type === 'way' && v[k].id === way.id) {
39980                           isAlongOnlyPath = true;
39981                           break;
39982                         }
39983                       }
39984                     }
39985
39986                     if (matchesViaTo) {
39987                       if (isOnly) {
39988                         restrict = {
39989                           id: restriction.id,
39990                           direct: matchesFrom,
39991                           from: f.id,
39992                           only: true,
39993                           end: true
39994                         };
39995                       } else {
39996                         restrict = {
39997                           id: restriction.id,
39998                           direct: matchesFrom,
39999                           from: f.id,
40000                           no: true,
40001                           end: true
40002                         };
40003                       }
40004                     } else {
40005                       // indirect - caused by a different nearby restriction
40006                       if (isAlongOnlyPath) {
40007                         restrict = {
40008                           id: restriction.id,
40009                           direct: false,
40010                           from: f.id,
40011                           only: true,
40012                           end: false
40013                         };
40014                       } else if (isOnly) {
40015                         restrict = {
40016                           id: restriction.id,
40017                           direct: false,
40018                           from: f.id,
40019                           no: true,
40020                           end: true
40021                         };
40022                       }
40023                     } // stop looking if we find a "direct" restriction (matching FROM, VIA, TO)
40024
40025
40026                     if (restrict && restrict.direct) break;
40027                   }
40028
40029                   nextWays.push({
40030                     way: way,
40031                     restrict: restrict
40032                   });
40033                 }
40034
40035                 nextWays.forEach(function (nextWay) {
40036                   step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
40037                 });
40038               } else {
40039                 // entity.type === 'way'
40040                 if (currPath.length >= 3) {
40041                   // this is a "complete" path..
40042                   var turnPath = currPath.slice(); // shallow copy
40043                   // an indirect restriction - only include the partial path (starting at FROM)
40044
40045                   if (matchedRestriction && matchedRestriction.direct === false) {
40046                     for (i = 0; i < turnPath.length; i++) {
40047                       if (turnPath[i] === matchedRestriction.from) {
40048                         turnPath = turnPath.slice(i);
40049                         break;
40050                       }
40051                     }
40052                   }
40053
40054                   var turn = pathToTurn(turnPath);
40055
40056                   if (turn) {
40057                     if (matchedRestriction) {
40058                       turn.restrictionID = matchedRestriction.id;
40059                       turn.no = matchedRestriction.no;
40060                       turn.only = matchedRestriction.only;
40061                       turn.direct = matchedRestriction.direct;
40062                     }
40063
40064                     turns.push(osmTurn(turn));
40065                   }
40066
40067                   if (currPath[0] === currPath[2]) return; // if we made a u-turn - stop here
40068                 }
40069
40070                 if (matchedRestriction && matchedRestriction.end) return; // don't advance any further
40071                 // which nodes can we step into?
40072
40073                 var n1 = vgraph.entity(entity.first());
40074                 var n2 = vgraph.entity(entity.last());
40075                 var dist = geoSphericalDistance(n1.loc, n2.loc);
40076                 var nextNodes = [];
40077
40078                 if (currPath.length > 1) {
40079                   if (dist > maxDistance) return; // the next node is too far
40080
40081                   if (!entity.__via) return; // this way is a leaf / can't be a via
40082                 }
40083
40084                 if (!entity.__oneWay && // bidirectional..
40085                 keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
40086                 currPath.indexOf(n1.id) === -1) {
40087                   // haven't seen it yet..
40088                   nextNodes.push(n1); // can advance to first node
40089                 }
40090
40091                 if (keyVertexIds.indexOf(n2.id) !== -1 && // key vertex..
40092                 currPath.indexOf(n2.id) === -1) {
40093                   // haven't seen it yet..
40094                   nextNodes.push(n2); // can advance to last node
40095                 }
40096
40097                 nextNodes.forEach(function (nextNode) {
40098                   // gather restrictions FROM this way
40099                   var fromRestrictions = vgraph.parentRelations(entity).filter(function (r) {
40100                     if (!r.isRestriction()) return false;
40101                     var f = r.memberByRole('from');
40102                     if (!f || f.id !== entity.id) return false;
40103                     var isOnly = /^only_/.test(r.tags.restriction);
40104                     if (!isOnly) return true; // `only_` restrictions only matter along the direction of the VIA - #4849
40105
40106                     var isOnlyVia = false;
40107                     var v = r.membersByRole('via');
40108
40109                     if (v.length === 1 && v[0].type === 'node') {
40110                       // via node
40111                       isOnlyVia = v[0].id === nextNode.id;
40112                     } else {
40113                       // via way(s)
40114                       for (var i = 0; i < v.length; i++) {
40115                         if (v[i].type !== 'way') continue;
40116                         var viaWay = vgraph.entity(v[i].id);
40117
40118                         if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
40119                           isOnlyVia = true;
40120                           break;
40121                         }
40122                       }
40123                     }
40124
40125                     return isOnlyVia;
40126                   });
40127                   step(nextNode, currPath, currRestrictions.concat(fromRestrictions), false);
40128                 });
40129               }
40130             } // assumes path is alternating way-node-way of odd length
40131
40132
40133             function pathToTurn(path) {
40134               if (path.length < 3) return;
40135               var fromWayId, fromNodeId, fromVertexId;
40136               var toWayId, toNodeId, toVertexId;
40137               var viaWayIds, viaNodeId, isUturn;
40138               fromWayId = path[0];
40139               toWayId = path[path.length - 1];
40140
40141               if (path.length === 3 && fromWayId === toWayId) {
40142                 // u turn
40143                 var way = vgraph.entity(fromWayId);
40144                 if (way.__oneWay) return null;
40145                 isUturn = true;
40146                 viaNodeId = fromVertexId = toVertexId = path[1];
40147                 fromNodeId = toNodeId = adjacentNode(fromWayId, viaNodeId);
40148               } else {
40149                 isUturn = false;
40150                 fromVertexId = path[1];
40151                 fromNodeId = adjacentNode(fromWayId, fromVertexId);
40152                 toVertexId = path[path.length - 2];
40153                 toNodeId = adjacentNode(toWayId, toVertexId);
40154
40155                 if (path.length === 3) {
40156                   viaNodeId = path[1];
40157                 } else {
40158                   viaWayIds = path.filter(function (entityId) {
40159                     return entityId[0] === 'w';
40160                   });
40161                   viaWayIds = viaWayIds.slice(1, viaWayIds.length - 1); // remove first, last
40162                 }
40163               }
40164
40165               return {
40166                 key: path.join('_'),
40167                 path: path,
40168                 from: {
40169                   node: fromNodeId,
40170                   way: fromWayId,
40171                   vertex: fromVertexId
40172                 },
40173                 via: {
40174                   node: viaNodeId,
40175                   ways: viaWayIds
40176                 },
40177                 to: {
40178                   node: toNodeId,
40179                   way: toWayId,
40180                   vertex: toVertexId
40181                 },
40182                 u: isUturn
40183               };
40184
40185               function adjacentNode(wayId, affixId) {
40186                 var nodes = vgraph.entity(wayId).nodes;
40187                 return affixId === nodes[0] ? nodes[1] : nodes[nodes.length - 2];
40188               }
40189             }
40190           };
40191
40192           return intersection;
40193         }
40194         function osmInferRestriction(graph, turn, projection) {
40195           var fromWay = graph.entity(turn.from.way);
40196           var fromNode = graph.entity(turn.from.node);
40197           var fromVertex = graph.entity(turn.from.vertex);
40198           var toWay = graph.entity(turn.to.way);
40199           var toNode = graph.entity(turn.to.node);
40200           var toVertex = graph.entity(turn.to.vertex);
40201           var fromOneWay = fromWay.tags.oneway === 'yes';
40202           var toOneWay = toWay.tags.oneway === 'yes';
40203           var angle = (geoAngle(fromVertex, fromNode, projection) - geoAngle(toVertex, toNode, projection)) * 180 / Math.PI;
40204
40205           while (angle < 0) {
40206             angle += 360;
40207           }
40208
40209           if (fromNode === toNode) {
40210             return 'no_u_turn';
40211           }
40212
40213           if ((angle < 23 || angle > 336) && fromOneWay && toOneWay) {
40214             return 'no_u_turn'; // wider tolerance for u-turn if both ways are oneway
40215           }
40216
40217           if ((angle < 40 || angle > 319) && fromOneWay && toOneWay && turn.from.vertex !== turn.to.vertex) {
40218             return 'no_u_turn'; // even wider tolerance for u-turn if there is a via way (from !== to)
40219           }
40220
40221           if (angle < 158) {
40222             return 'no_right_turn';
40223           }
40224
40225           if (angle > 202) {
40226             return 'no_left_turn';
40227           }
40228
40229           return 'no_straight_on';
40230         }
40231
40232         function actionMergePolygon(ids, newRelationId) {
40233           function groupEntities(graph) {
40234             var entities = ids.map(function (id) {
40235               return graph.entity(id);
40236             });
40237             var geometryGroups = utilArrayGroupBy(entities, function (entity) {
40238               if (entity.type === 'way' && entity.isClosed()) {
40239                 return 'closedWay';
40240               } else if (entity.type === 'relation' && entity.isMultipolygon()) {
40241                 return 'multipolygon';
40242               } else {
40243                 return 'other';
40244               }
40245             });
40246             return Object.assign({
40247               closedWay: [],
40248               multipolygon: [],
40249               other: []
40250             }, geometryGroups);
40251           }
40252
40253           var action = function action(graph) {
40254             var entities = groupEntities(graph); // An array representing all the polygons that are part of the multipolygon.
40255             //
40256             // Each element is itself an array of objects with an id property, and has a
40257             // locs property which is an array of the locations forming the polygon.
40258
40259             var polygons = entities.multipolygon.reduce(function (polygons, m) {
40260               return polygons.concat(osmJoinWays(m.members, graph));
40261             }, []).concat(entities.closedWay.map(function (d) {
40262               var member = [{
40263                 id: d.id
40264               }];
40265               member.nodes = graph.childNodes(d);
40266               return member;
40267             })); // contained is an array of arrays of boolean values,
40268             // where contained[j][k] is true iff the jth way is
40269             // contained by the kth way.
40270
40271             var contained = polygons.map(function (w, i) {
40272               return polygons.map(function (d, n) {
40273                 if (i === n) return null;
40274                 return geoPolygonContainsPolygon(d.nodes.map(function (n) {
40275                   return n.loc;
40276                 }), w.nodes.map(function (n) {
40277                   return n.loc;
40278                 }));
40279               });
40280             }); // Sort all polygons as either outer or inner ways
40281
40282             var members = [];
40283             var outer = true;
40284
40285             while (polygons.length) {
40286               extractUncontained(polygons);
40287               polygons = polygons.filter(isContained);
40288               contained = contained.filter(isContained).map(filterContained);
40289             }
40290
40291             function isContained(d, i) {
40292               return contained[i].some(function (val) {
40293                 return val;
40294               });
40295             }
40296
40297             function filterContained(d) {
40298               return d.filter(isContained);
40299             }
40300
40301             function extractUncontained(polygons) {
40302               polygons.forEach(function (d, i) {
40303                 if (!isContained(d, i)) {
40304                   d.forEach(function (member) {
40305                     members.push({
40306                       type: 'way',
40307                       id: member.id,
40308                       role: outer ? 'outer' : 'inner'
40309                     });
40310                   });
40311                 }
40312               });
40313               outer = !outer;
40314             } // Move all tags to one relation
40315
40316
40317             var relation = entities.multipolygon[0] || osmRelation({
40318               id: newRelationId,
40319               tags: {
40320                 type: 'multipolygon'
40321               }
40322             });
40323             entities.multipolygon.slice(1).forEach(function (m) {
40324               relation = relation.mergeTags(m.tags);
40325               graph = graph.remove(m);
40326             });
40327             entities.closedWay.forEach(function (way) {
40328               function isThisOuter(m) {
40329                 return m.id === way.id && m.role !== 'inner';
40330               }
40331
40332               if (members.some(isThisOuter)) {
40333                 relation = relation.mergeTags(way.tags);
40334                 graph = graph.replace(way.update({
40335                   tags: {}
40336                 }));
40337               }
40338             });
40339             return graph.replace(relation.update({
40340               members: members,
40341               tags: utilObjectOmit(relation.tags, ['area'])
40342             }));
40343           };
40344
40345           action.disabled = function (graph) {
40346             var entities = groupEntities(graph);
40347
40348             if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
40349               return 'not_eligible';
40350             }
40351
40352             if (!entities.multipolygon.every(function (r) {
40353               return r.isComplete(graph);
40354             })) {
40355               return 'incomplete_relation';
40356             }
40357
40358             if (!entities.multipolygon.length) {
40359               var sharedMultipolygons = [];
40360               entities.closedWay.forEach(function (way, i) {
40361                 if (i === 0) {
40362                   sharedMultipolygons = graph.parentMultipolygons(way);
40363                 } else {
40364                   sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
40365                 }
40366               });
40367               sharedMultipolygons = sharedMultipolygons.filter(function (relation) {
40368                 return relation.members.length === entities.closedWay.length;
40369               });
40370
40371               if (sharedMultipolygons.length) {
40372                 // don't create a new multipolygon if it'd be redundant
40373                 return 'not_eligible';
40374               }
40375             } else if (entities.closedWay.some(function (way) {
40376               return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
40377             })) {
40378               // don't add a way to a multipolygon again if it's already a member
40379               return 'not_eligible';
40380             }
40381           };
40382
40383           return action;
40384         }
40385
40386         var FORCED$2 = descriptors && fails(function () {
40387           // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
40388           return Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags').get.call({ dotAll: true, sticky: true }) !== 'sy';
40389         });
40390
40391         // `RegExp.prototype.flags` getter
40392         // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
40393         if (FORCED$2) objectDefineProperty.f(RegExp.prototype, 'flags', {
40394           configurable: true,
40395           get: regexpFlags
40396         });
40397
40398         var fastDeepEqual = function equal(a, b) {
40399           if (a === b) return true;
40400
40401           if (a && b && _typeof(a) == 'object' && _typeof(b) == 'object') {
40402             if (a.constructor !== b.constructor) return false;
40403             var length, i, keys;
40404
40405             if (Array.isArray(a)) {
40406               length = a.length;
40407               if (length != b.length) return false;
40408
40409               for (i = length; i-- !== 0;) {
40410                 if (!equal(a[i], b[i])) return false;
40411               }
40412
40413               return true;
40414             }
40415
40416             if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
40417             if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
40418             if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
40419             keys = Object.keys(a);
40420             length = keys.length;
40421             if (length !== Object.keys(b).length) return false;
40422
40423             for (i = length; i-- !== 0;) {
40424               if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
40425             }
40426
40427             for (i = length; i-- !== 0;) {
40428               var key = keys[i];
40429               if (!equal(a[key], b[key])) return false;
40430             }
40431
40432             return true;
40433           } // true if both NaN, false otherwise
40434
40435
40436           return a !== a && b !== b;
40437         };
40438
40439         // J. W. Hunt and M. D. McIlroy, An algorithm for differential buffer
40440         // comparison, Bell Telephone Laboratories CSTR #41 (1976)
40441         // http://www.cs.dartmouth.edu/~doug/
40442         // https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
40443         //
40444         // Expects two arrays, finds longest common sequence
40445
40446         function LCS(buffer1, buffer2) {
40447           var equivalenceClasses = {};
40448
40449           for (var j = 0; j < buffer2.length; j++) {
40450             var item = buffer2[j];
40451
40452             if (equivalenceClasses[item]) {
40453               equivalenceClasses[item].push(j);
40454             } else {
40455               equivalenceClasses[item] = [j];
40456             }
40457           }
40458
40459           var NULLRESULT = {
40460             buffer1index: -1,
40461             buffer2index: -1,
40462             chain: null
40463           };
40464           var candidates = [NULLRESULT];
40465
40466           for (var i = 0; i < buffer1.length; i++) {
40467             var _item = buffer1[i];
40468             var buffer2indices = equivalenceClasses[_item] || [];
40469             var r = 0;
40470             var c = candidates[0];
40471
40472             for (var jx = 0; jx < buffer2indices.length; jx++) {
40473               var _j = buffer2indices[jx];
40474               var s = void 0;
40475
40476               for (s = r; s < candidates.length; s++) {
40477                 if (candidates[s].buffer2index < _j && (s === candidates.length - 1 || candidates[s + 1].buffer2index > _j)) {
40478                   break;
40479                 }
40480               }
40481
40482               if (s < candidates.length) {
40483                 var newCandidate = {
40484                   buffer1index: i,
40485                   buffer2index: _j,
40486                   chain: candidates[s]
40487                 };
40488
40489                 if (r === candidates.length) {
40490                   candidates.push(c);
40491                 } else {
40492                   candidates[r] = c;
40493                 }
40494
40495                 r = s + 1;
40496                 c = newCandidate;
40497
40498                 if (r === candidates.length) {
40499                   break; // no point in examining further (j)s
40500                 }
40501               }
40502             }
40503
40504             candidates[r] = c;
40505           } // At this point, we know the LCS: it's in the reverse of the
40506           // linked-list through .chain of candidates[candidates.length - 1].
40507
40508
40509           return candidates[candidates.length - 1];
40510         } // We apply the LCS to build a 'comm'-style picture of the
40511         // offsets and lengths of mismatched chunks in the input
40512         // buffers. This is used by diff3MergeRegions.
40513
40514
40515         function diffIndices(buffer1, buffer2) {
40516           var lcs = LCS(buffer1, buffer2);
40517           var result = [];
40518           var tail1 = buffer1.length;
40519           var tail2 = buffer2.length;
40520
40521           for (var candidate = lcs; candidate !== null; candidate = candidate.chain) {
40522             var mismatchLength1 = tail1 - candidate.buffer1index - 1;
40523             var mismatchLength2 = tail2 - candidate.buffer2index - 1;
40524             tail1 = candidate.buffer1index;
40525             tail2 = candidate.buffer2index;
40526
40527             if (mismatchLength1 || mismatchLength2) {
40528               result.push({
40529                 buffer1: [tail1 + 1, mismatchLength1],
40530                 buffer1Content: buffer1.slice(tail1 + 1, tail1 + 1 + mismatchLength1),
40531                 buffer2: [tail2 + 1, mismatchLength2],
40532                 buffer2Content: buffer2.slice(tail2 + 1, tail2 + 1 + mismatchLength2)
40533               });
40534             }
40535           }
40536
40537           result.reverse();
40538           return result;
40539         } // We apply the LCS to build a JSON representation of a
40540         // independently derived from O, returns a fairly complicated
40541         // internal representation of merge decisions it's taken. The
40542         // interested reader may wish to consult
40543         //
40544         // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce.
40545         // 'A Formal Investigation of ' In Arvind and Prasad,
40546         // editors, Foundations of Software Technology and Theoretical
40547         // Computer Science (FSTTCS), December 2007.
40548         //
40549         // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
40550         //
40551
40552
40553         function diff3MergeRegions(a, o, b) {
40554           // "hunks" are array subsets where `a` or `b` are different from `o`
40555           // https://www.gnu.org/software/diffutils/manual/html_node/diff3-Hunks.html
40556           var hunks = [];
40557
40558           function addHunk(h, ab) {
40559             hunks.push({
40560               ab: ab,
40561               oStart: h.buffer1[0],
40562               oLength: h.buffer1[1],
40563               // length of o to remove
40564               abStart: h.buffer2[0],
40565               abLength: h.buffer2[1] // length of a/b to insert
40566               // abContent: (ab === 'a' ? a : b).slice(h.buffer2[0], h.buffer2[0] + h.buffer2[1])
40567
40568             });
40569           }
40570
40571           diffIndices(o, a).forEach(function (item) {
40572             return addHunk(item, 'a');
40573           });
40574           diffIndices(o, b).forEach(function (item) {
40575             return addHunk(item, 'b');
40576           });
40577           hunks.sort(function (x, y) {
40578             return x.oStart - y.oStart;
40579           });
40580           var results = [];
40581           var currOffset = 0;
40582
40583           function advanceTo(endOffset) {
40584             if (endOffset > currOffset) {
40585               results.push({
40586                 stable: true,
40587                 buffer: 'o',
40588                 bufferStart: currOffset,
40589                 bufferLength: endOffset - currOffset,
40590                 bufferContent: o.slice(currOffset, endOffset)
40591               });
40592               currOffset = endOffset;
40593             }
40594           }
40595
40596           while (hunks.length) {
40597             var hunk = hunks.shift();
40598             var regionStart = hunk.oStart;
40599             var regionEnd = hunk.oStart + hunk.oLength;
40600             var regionHunks = [hunk];
40601             advanceTo(regionStart); // Try to pull next overlapping hunk into this region
40602
40603             while (hunks.length) {
40604               var nextHunk = hunks[0];
40605               var nextHunkStart = nextHunk.oStart;
40606               if (nextHunkStart > regionEnd) break; // no overlap
40607
40608               regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
40609               regionHunks.push(hunks.shift());
40610             }
40611
40612             if (regionHunks.length === 1) {
40613               // Only one hunk touches this region, meaning that there is no conflict here.
40614               // Either `a` or `b` is inserting into a region of `o` unchanged by the other.
40615               if (hunk.abLength > 0) {
40616                 var buffer = hunk.ab === 'a' ? a : b;
40617                 results.push({
40618                   stable: true,
40619                   buffer: hunk.ab,
40620                   bufferStart: hunk.abStart,
40621                   bufferLength: hunk.abLength,
40622                   bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
40623                 });
40624               }
40625             } else {
40626               // A true a/b conflict. Determine the bounds involved from `a`, `o`, and `b`.
40627               // Effectively merge all the `a` hunks into one giant hunk, then do the
40628               // same for the `b` hunks; then, correct for skew in the regions of `o`
40629               // that each side changed, and report appropriate spans for the three sides.
40630               var bounds = {
40631                 a: [a.length, -1, o.length, -1],
40632                 b: [b.length, -1, o.length, -1]
40633               };
40634
40635               while (regionHunks.length) {
40636                 hunk = regionHunks.shift();
40637                 var oStart = hunk.oStart;
40638                 var oEnd = oStart + hunk.oLength;
40639                 var abStart = hunk.abStart;
40640                 var abEnd = abStart + hunk.abLength;
40641                 var _b = bounds[hunk.ab];
40642                 _b[0] = Math.min(abStart, _b[0]);
40643                 _b[1] = Math.max(abEnd, _b[1]);
40644                 _b[2] = Math.min(oStart, _b[2]);
40645                 _b[3] = Math.max(oEnd, _b[3]);
40646               }
40647
40648               var aStart = bounds.a[0] + (regionStart - bounds.a[2]);
40649               var aEnd = bounds.a[1] + (regionEnd - bounds.a[3]);
40650               var bStart = bounds.b[0] + (regionStart - bounds.b[2]);
40651               var bEnd = bounds.b[1] + (regionEnd - bounds.b[3]);
40652               var result = {
40653                 stable: false,
40654                 aStart: aStart,
40655                 aLength: aEnd - aStart,
40656                 aContent: a.slice(aStart, aEnd),
40657                 oStart: regionStart,
40658                 oLength: regionEnd - regionStart,
40659                 oContent: o.slice(regionStart, regionEnd),
40660                 bStart: bStart,
40661                 bLength: bEnd - bStart,
40662                 bContent: b.slice(bStart, bEnd)
40663               };
40664               results.push(result);
40665             }
40666
40667             currOffset = regionEnd;
40668           }
40669
40670           advanceTo(o.length);
40671           return results;
40672         } // Applies the output of diff3MergeRegions to actually
40673         // construct the merged buffer; the returned result alternates
40674         // between 'ok' and 'conflict' blocks.
40675         // A "false conflict" is where `a` and `b` both change the same from `o`
40676
40677
40678         function diff3Merge(a, o, b, options) {
40679           var defaults = {
40680             excludeFalseConflicts: true,
40681             stringSeparator: /\s+/
40682           };
40683           options = Object.assign(defaults, options);
40684           var aString = typeof a === 'string';
40685           var oString = typeof o === 'string';
40686           var bString = typeof b === 'string';
40687           if (aString) a = a.split(options.stringSeparator);
40688           if (oString) o = o.split(options.stringSeparator);
40689           if (bString) b = b.split(options.stringSeparator);
40690           var results = [];
40691           var regions = diff3MergeRegions(a, o, b);
40692           var okBuffer = [];
40693
40694           function flushOk() {
40695             if (okBuffer.length) {
40696               results.push({
40697                 ok: okBuffer
40698               });
40699             }
40700
40701             okBuffer = [];
40702           }
40703
40704           function isFalseConflict(a, b) {
40705             if (a.length !== b.length) return false;
40706
40707             for (var i = 0; i < a.length; i++) {
40708               if (a[i] !== b[i]) return false;
40709             }
40710
40711             return true;
40712           }
40713
40714           regions.forEach(function (region) {
40715             if (region.stable) {
40716               var _okBuffer;
40717
40718               (_okBuffer = okBuffer).push.apply(_okBuffer, _toConsumableArray(region.bufferContent));
40719             } else {
40720               if (options.excludeFalseConflicts && isFalseConflict(region.aContent, region.bContent)) {
40721                 var _okBuffer2;
40722
40723                 (_okBuffer2 = okBuffer).push.apply(_okBuffer2, _toConsumableArray(region.aContent));
40724               } else {
40725                 flushOk();
40726                 results.push({
40727                   conflict: {
40728                     a: region.aContent,
40729                     aIndex: region.aStart,
40730                     o: region.oContent,
40731                     oIndex: region.oStart,
40732                     b: region.bContent,
40733                     bIndex: region.bStart
40734                   }
40735                 });
40736               }
40737             }
40738           });
40739           flushOk();
40740           return results;
40741         }
40742
40743         function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTags, formatUser) {
40744           discardTags = discardTags || {};
40745           var _option = 'safe'; // 'safe', 'force_local', 'force_remote'
40746
40747           var _conflicts = [];
40748
40749           function user(d) {
40750             return typeof formatUser === 'function' ? formatUser(d) : d;
40751           }
40752
40753           function mergeLocation(remote, target) {
40754             function pointEqual(a, b) {
40755               var epsilon = 1e-6;
40756               return Math.abs(a[0] - b[0]) < epsilon && Math.abs(a[1] - b[1]) < epsilon;
40757             }
40758
40759             if (_option === 'force_local' || pointEqual(target.loc, remote.loc)) {
40760               return target;
40761             }
40762
40763             if (_option === 'force_remote') {
40764               return target.update({
40765                 loc: remote.loc
40766               });
40767             }
40768
40769             _conflicts.push(_t('merge_remote_changes.conflict.location', {
40770               user: user(remote.user)
40771             }));
40772
40773             return target;
40774           }
40775
40776           function mergeNodes(base, remote, target) {
40777             if (_option === 'force_local' || fastDeepEqual(target.nodes, remote.nodes)) {
40778               return target;
40779             }
40780
40781             if (_option === 'force_remote') {
40782               return target.update({
40783                 nodes: remote.nodes
40784               });
40785             }
40786
40787             var ccount = _conflicts.length;
40788             var o = base.nodes || [];
40789             var a = target.nodes || [];
40790             var b = remote.nodes || [];
40791             var nodes = [];
40792             var hunks = diff3Merge(a, o, b, {
40793               excludeFalseConflicts: true
40794             });
40795
40796             for (var i = 0; i < hunks.length; i++) {
40797               var hunk = hunks[i];
40798
40799               if (hunk.ok) {
40800                 nodes.push.apply(nodes, hunk.ok);
40801               } else {
40802                 // for all conflicts, we can assume c.a !== c.b
40803                 // because `diff3Merge` called with `true` option to exclude false conflicts..
40804                 var c = hunk.conflict;
40805
40806                 if (fastDeepEqual(c.o, c.a)) {
40807                   // only changed remotely
40808                   nodes.push.apply(nodes, c.b);
40809                 } else if (fastDeepEqual(c.o, c.b)) {
40810                   // only changed locally
40811                   nodes.push.apply(nodes, c.a);
40812                 } else {
40813                   // changed both locally and remotely
40814                   _conflicts.push(_t('merge_remote_changes.conflict.nodelist', {
40815                     user: user(remote.user)
40816                   }));
40817
40818                   break;
40819                 }
40820               }
40821             }
40822
40823             return _conflicts.length === ccount ? target.update({
40824               nodes: nodes
40825             }) : target;
40826           }
40827
40828           function mergeChildren(targetWay, children, updates, graph) {
40829             function isUsed(node, targetWay) {
40830               var hasInterestingParent = graph.parentWays(node).some(function (way) {
40831                 return way.id !== targetWay.id;
40832               });
40833               return node.hasInterestingTags() || hasInterestingParent || graph.parentRelations(node).length > 0;
40834             }
40835
40836             var ccount = _conflicts.length;
40837
40838             for (var i = 0; i < children.length; i++) {
40839               var id = children[i];
40840               var node = graph.hasEntity(id); // remove unused childNodes..
40841
40842               if (targetWay.nodes.indexOf(id) === -1) {
40843                 if (node && !isUsed(node, targetWay)) {
40844                   updates.removeIds.push(id);
40845                 }
40846
40847                 continue;
40848               } // restore used childNodes..
40849
40850
40851               var local = localGraph.hasEntity(id);
40852               var remote = remoteGraph.hasEntity(id);
40853               var target;
40854
40855               if (_option === 'force_remote' && remote && remote.visible) {
40856                 updates.replacements.push(remote);
40857               } else if (_option === 'force_local' && local) {
40858                 target = osmEntity(local);
40859
40860                 if (remote) {
40861                   target = target.update({
40862                     version: remote.version
40863                   });
40864                 }
40865
40866                 updates.replacements.push(target);
40867               } else if (_option === 'safe' && local && remote && local.version !== remote.version) {
40868                 target = osmEntity(local, {
40869                   version: remote.version
40870                 });
40871
40872                 if (remote.visible) {
40873                   target = mergeLocation(remote, target);
40874                 } else {
40875                   _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
40876                     user: user(remote.user)
40877                   }));
40878                 }
40879
40880                 if (_conflicts.length !== ccount) break;
40881                 updates.replacements.push(target);
40882               }
40883             }
40884
40885             return targetWay;
40886           }
40887
40888           function updateChildren(updates, graph) {
40889             for (var i = 0; i < updates.replacements.length; i++) {
40890               graph = graph.replace(updates.replacements[i]);
40891             }
40892
40893             if (updates.removeIds.length) {
40894               graph = actionDeleteMultiple(updates.removeIds)(graph);
40895             }
40896
40897             return graph;
40898           }
40899
40900           function mergeMembers(remote, target) {
40901             if (_option === 'force_local' || fastDeepEqual(target.members, remote.members)) {
40902               return target;
40903             }
40904
40905             if (_option === 'force_remote') {
40906               return target.update({
40907                 members: remote.members
40908               });
40909             }
40910
40911             _conflicts.push(_t('merge_remote_changes.conflict.memberlist', {
40912               user: user(remote.user)
40913             }));
40914
40915             return target;
40916           }
40917
40918           function mergeTags(base, remote, target) {
40919             if (_option === 'force_local' || fastDeepEqual(target.tags, remote.tags)) {
40920               return target;
40921             }
40922
40923             if (_option === 'force_remote') {
40924               return target.update({
40925                 tags: remote.tags
40926               });
40927             }
40928
40929             var ccount = _conflicts.length;
40930             var o = base.tags || {};
40931             var a = target.tags || {};
40932             var b = remote.tags || {};
40933             var keys = utilArrayUnion(utilArrayUnion(Object.keys(o), Object.keys(a)), Object.keys(b)).filter(function (k) {
40934               return !discardTags[k];
40935             });
40936             var tags = Object.assign({}, a); // shallow copy
40937
40938             var changed = false;
40939
40940             for (var i = 0; i < keys.length; i++) {
40941               var k = keys[i];
40942
40943               if (o[k] !== b[k] && a[k] !== b[k]) {
40944                 // changed remotely..
40945                 if (o[k] !== a[k]) {
40946                   // changed locally..
40947                   _conflicts.push(_t('merge_remote_changes.conflict.tags', {
40948                     tag: k,
40949                     local: a[k],
40950                     remote: b[k],
40951                     user: user(remote.user)
40952                   }));
40953                 } else {
40954                   // unchanged locally, accept remote change..
40955                   if (b.hasOwnProperty(k)) {
40956                     tags[k] = b[k];
40957                   } else {
40958                     delete tags[k];
40959                   }
40960
40961                   changed = true;
40962                 }
40963               }
40964             }
40965
40966             return changed && _conflicts.length === ccount ? target.update({
40967               tags: tags
40968             }) : target;
40969           } //  `graph.base()` is the common ancestor of the two graphs.
40970           //  `localGraph` contains user's edits up to saving
40971           //  `remoteGraph` contains remote edits to modified nodes
40972           //  `graph` must be a descendent of `localGraph` and may include
40973           //      some conflict resolution actions performed on it.
40974           //
40975           //                  --- ... --- `localGraph` -- ... -- `graph`
40976           //                 /
40977           //  `graph.base()` --- ... --- `remoteGraph`
40978           //
40979
40980
40981           var action = function action(graph) {
40982             var updates = {
40983               replacements: [],
40984               removeIds: []
40985             };
40986             var base = graph.base().entities[id];
40987             var local = localGraph.entity(id);
40988             var remote = remoteGraph.entity(id);
40989             var target = osmEntity(local, {
40990               version: remote.version
40991             }); // delete/undelete
40992
40993             if (!remote.visible) {
40994               if (_option === 'force_remote') {
40995                 return actionDeleteMultiple([id])(graph);
40996               } else if (_option === 'force_local') {
40997                 if (target.type === 'way') {
40998                   target = mergeChildren(target, utilArrayUniq(local.nodes), updates, graph);
40999                   graph = updateChildren(updates, graph);
41000                 }
41001
41002                 return graph.replace(target);
41003               } else {
41004                 _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
41005                   user: user(remote.user)
41006                 }));
41007
41008                 return graph; // do nothing
41009               }
41010             } // merge
41011
41012
41013             if (target.type === 'node') {
41014               target = mergeLocation(remote, target);
41015             } else if (target.type === 'way') {
41016               // pull in any child nodes that may not be present locally..
41017               graph.rebase(remoteGraph.childNodes(remote), [graph], false);
41018               target = mergeNodes(base, remote, target);
41019               target = mergeChildren(target, utilArrayUnion(local.nodes, remote.nodes), updates, graph);
41020             } else if (target.type === 'relation') {
41021               target = mergeMembers(remote, target);
41022             }
41023
41024             target = mergeTags(base, remote, target);
41025
41026             if (!_conflicts.length) {
41027               graph = updateChildren(updates, graph).replace(target);
41028             }
41029
41030             return graph;
41031           };
41032
41033           action.withOption = function (opt) {
41034             _option = opt;
41035             return action;
41036           };
41037
41038           action.conflicts = function () {
41039             return _conflicts;
41040           };
41041
41042           return action;
41043         }
41044
41045         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
41046
41047         function actionMove(moveIDs, tryDelta, projection, cache) {
41048           var _delta = tryDelta;
41049
41050           function setupCache(graph) {
41051             function canMove(nodeID) {
41052               // Allow movement of any node that is in the selectedIDs list..
41053               if (moveIDs.indexOf(nodeID) !== -1) return true; // Allow movement of a vertex where 2 ways meet..
41054
41055               var parents = graph.parentWays(graph.entity(nodeID));
41056               if (parents.length < 3) return true; // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
41057
41058               var parentsMoving = parents.every(function (way) {
41059                 return cache.moving[way.id];
41060               });
41061               if (!parentsMoving) delete cache.moving[nodeID];
41062               return parentsMoving;
41063             }
41064
41065             function cacheEntities(ids) {
41066               for (var i = 0; i < ids.length; i++) {
41067                 var id = ids[i];
41068                 if (cache.moving[id]) continue;
41069                 cache.moving[id] = true;
41070                 var entity = graph.hasEntity(id);
41071                 if (!entity) continue;
41072
41073                 if (entity.type === 'node') {
41074                   cache.nodes.push(id);
41075                   cache.startLoc[id] = entity.loc;
41076                 } else if (entity.type === 'way') {
41077                   cache.ways.push(id);
41078                   cacheEntities(entity.nodes);
41079                 } else {
41080                   cacheEntities(entity.members.map(function (member) {
41081                     return member.id;
41082                   }));
41083                 }
41084               }
41085             }
41086
41087             function cacheIntersections(ids) {
41088               function isEndpoint(way, id) {
41089                 return !way.isClosed() && !!way.affix(id);
41090               }
41091
41092               for (var i = 0; i < ids.length; i++) {
41093                 var id = ids[i]; // consider only intersections with 1 moved and 1 unmoved way.
41094
41095                 var childNodes = graph.childNodes(graph.entity(id));
41096
41097                 for (var j = 0; j < childNodes.length; j++) {
41098                   var node = childNodes[j];
41099                   var parents = graph.parentWays(node);
41100                   if (parents.length !== 2) continue;
41101                   var moved = graph.entity(id);
41102                   var unmoved = null;
41103
41104                   for (var k = 0; k < parents.length; k++) {
41105                     var way = parents[k];
41106
41107                     if (!cache.moving[way.id]) {
41108                       unmoved = way;
41109                       break;
41110                     }
41111                   }
41112
41113                   if (!unmoved) continue; // exclude ways that are overly connected..
41114
41115                   if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2) continue;
41116                   if (moved.isArea() || unmoved.isArea()) continue;
41117                   cache.intersections.push({
41118                     nodeId: node.id,
41119                     movedId: moved.id,
41120                     unmovedId: unmoved.id,
41121                     movedIsEP: isEndpoint(moved, node.id),
41122                     unmovedIsEP: isEndpoint(unmoved, node.id)
41123                   });
41124                 }
41125               }
41126             }
41127
41128             if (!cache) {
41129               cache = {};
41130             }
41131
41132             if (!cache.ok) {
41133               cache.moving = {};
41134               cache.intersections = [];
41135               cache.replacedVertex = {};
41136               cache.startLoc = {};
41137               cache.nodes = [];
41138               cache.ways = [];
41139               cacheEntities(moveIDs);
41140               cacheIntersections(cache.ways);
41141               cache.nodes = cache.nodes.filter(canMove);
41142               cache.ok = true;
41143             }
41144           } // Place a vertex where the moved vertex used to be, to preserve way shape..
41145           //
41146           //  Start:
41147           //      b ---- e
41148           //     / \
41149           //    /   \
41150           //   /     \
41151           //  a       c
41152           //
41153           //      *               node '*' added to preserve shape
41154           //     / \
41155           //    /   b ---- e      way `b,e` moved here:
41156           //   /     \
41157           //  a       c
41158           //
41159           //
41160
41161
41162           function replaceMovedVertex(nodeId, wayId, graph, delta) {
41163             var way = graph.entity(wayId);
41164             var moved = graph.entity(nodeId);
41165             var movedIndex = way.nodes.indexOf(nodeId);
41166             var len, prevIndex, nextIndex;
41167
41168             if (way.isClosed()) {
41169               len = way.nodes.length - 1;
41170               prevIndex = (movedIndex + len - 1) % len;
41171               nextIndex = (movedIndex + len + 1) % len;
41172             } else {
41173               len = way.nodes.length;
41174               prevIndex = movedIndex - 1;
41175               nextIndex = movedIndex + 1;
41176             }
41177
41178             var prev = graph.hasEntity(way.nodes[prevIndex]);
41179             var next = graph.hasEntity(way.nodes[nextIndex]); // Don't add orig vertex at endpoint..
41180
41181             if (!prev || !next) return graph;
41182             var key = wayId + '_' + nodeId;
41183             var orig = cache.replacedVertex[key];
41184
41185             if (!orig) {
41186               orig = osmNode();
41187               cache.replacedVertex[key] = orig;
41188               cache.startLoc[orig.id] = cache.startLoc[nodeId];
41189             }
41190
41191             var start, end;
41192
41193             if (delta) {
41194               start = projection(cache.startLoc[nodeId]);
41195               end = projection.invert(geoVecAdd(start, delta));
41196             } else {
41197               end = cache.startLoc[nodeId];
41198             }
41199
41200             orig = orig.move(end);
41201             var angle = Math.abs(geoAngle(orig, prev, projection) - geoAngle(orig, next, projection)) * 180 / Math.PI; // Don't add orig vertex if it would just make a straight line..
41202
41203             if (angle > 175 && angle < 185) return graph; // moving forward or backward along way?
41204
41205             var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection);
41206             var p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection);
41207             var d1 = geoPathLength(p1);
41208             var d2 = geoPathLength(p2);
41209             var insertAt = d1 <= d2 ? movedIndex : nextIndex; // moving around closed loop?
41210
41211             if (way.isClosed() && insertAt === 0) insertAt = len;
41212             way = way.addNode(orig.id, insertAt);
41213             return graph.replace(orig).replace(way);
41214           } // Remove duplicate vertex that might have been added by
41215           // replaceMovedVertex.  This is done after the unzorro checks.
41216
41217
41218           function removeDuplicateVertices(wayId, graph) {
41219             var way = graph.entity(wayId);
41220             var epsilon = 1e-6;
41221             var prev, curr;
41222
41223             function isInteresting(node, graph) {
41224               return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
41225             }
41226
41227             for (var i = 0; i < way.nodes.length; i++) {
41228               curr = graph.entity(way.nodes[i]);
41229
41230               if (prev && curr && geoVecEqual(prev.loc, curr.loc, epsilon)) {
41231                 if (!isInteresting(prev, graph)) {
41232                   way = way.removeNode(prev.id);
41233                   graph = graph.replace(way).remove(prev);
41234                 } else if (!isInteresting(curr, graph)) {
41235                   way = way.removeNode(curr.id);
41236                   graph = graph.replace(way).remove(curr);
41237                 }
41238               }
41239
41240               prev = curr;
41241             }
41242
41243             return graph;
41244           } // Reorder nodes around intersections that have moved..
41245           //
41246           //  Start:                way1.nodes: b,e         (moving)
41247           //  a - b - c ----- d     way2.nodes: a,b,c,d     (static)
41248           //      |                 vertex: b
41249           //      e                 isEP1: true,  isEP2, false
41250           //
41251           //  way1 `b,e` moved here:
41252           //  a ----- c = b - d
41253           //              |
41254           //              e
41255           //
41256           //  reorder nodes         way1.nodes: b,e
41257           //  a ----- c - b - d     way2.nodes: a,c,b,d
41258           //              |
41259           //              e
41260           //
41261
41262
41263           function unZorroIntersection(intersection, graph) {
41264             var vertex = graph.entity(intersection.nodeId);
41265             var way1 = graph.entity(intersection.movedId);
41266             var way2 = graph.entity(intersection.unmovedId);
41267             var isEP1 = intersection.movedIsEP;
41268             var isEP2 = intersection.unmovedIsEP; // don't move the vertex if it is the endpoint of both ways.
41269
41270             if (isEP1 && isEP2) return graph;
41271             var nodes1 = graph.childNodes(way1).filter(function (n) {
41272               return n !== vertex;
41273             });
41274             var nodes2 = graph.childNodes(way2).filter(function (n) {
41275               return n !== vertex;
41276             });
41277             if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
41278             if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
41279             var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection);
41280             var edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection);
41281             var loc; // snap vertex to nearest edge (or some point between them)..
41282
41283             if (!isEP1 && !isEP2) {
41284               var epsilon = 1e-6,
41285                   maxIter = 10;
41286
41287               for (var i = 0; i < maxIter; i++) {
41288                 loc = geoVecInterp(edge1.loc, edge2.loc, 0.5);
41289                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
41290                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
41291                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
41292               }
41293             } else if (!isEP1) {
41294               loc = edge1.loc;
41295             } else {
41296               loc = edge2.loc;
41297             }
41298
41299             graph = graph.replace(vertex.move(loc)); // if zorro happened, reorder nodes..
41300
41301             if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
41302               way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
41303               graph = graph.replace(way1);
41304             }
41305
41306             if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
41307               way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
41308               graph = graph.replace(way2);
41309             }
41310
41311             return graph;
41312           }
41313
41314           function cleanupIntersections(graph) {
41315             for (var i = 0; i < cache.intersections.length; i++) {
41316               var obj = cache.intersections[i];
41317               graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, _delta);
41318               graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
41319               graph = unZorroIntersection(obj, graph);
41320               graph = removeDuplicateVertices(obj.movedId, graph);
41321               graph = removeDuplicateVertices(obj.unmovedId, graph);
41322             }
41323
41324             return graph;
41325           } // check if moving way endpoint can cross an unmoved way, if so limit delta..
41326
41327
41328           function limitDelta(graph) {
41329             function moveNode(loc) {
41330               return geoVecAdd(projection(loc), _delta);
41331             }
41332
41333             for (var i = 0; i < cache.intersections.length; i++) {
41334               var obj = cache.intersections[i]; // Don't limit movement if this is vertex joins 2 endpoints..
41335
41336               if (obj.movedIsEP && obj.unmovedIsEP) continue; // Don't limit movement if this vertex is not an endpoint anyway..
41337
41338               if (!obj.movedIsEP) continue;
41339               var node = graph.entity(obj.nodeId);
41340               var start = projection(node.loc);
41341               var end = geoVecAdd(start, _delta);
41342               var movedNodes = graph.childNodes(graph.entity(obj.movedId));
41343               var movedPath = movedNodes.map(function (n) {
41344                 return moveNode(n.loc);
41345               });
41346               var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
41347               var unmovedPath = unmovedNodes.map(function (n) {
41348                 return projection(n.loc);
41349               });
41350               var hits = geoPathIntersections(movedPath, unmovedPath);
41351
41352               for (var j = 0; i < hits.length; i++) {
41353                 if (geoVecEqual(hits[j], end)) continue;
41354                 var edge = geoChooseEdge(unmovedNodes, end, projection);
41355                 _delta = geoVecSubtract(projection(edge.loc), start);
41356               }
41357             }
41358           }
41359
41360           var action = function action(graph) {
41361             if (_delta[0] === 0 && _delta[1] === 0) return graph;
41362             setupCache(graph);
41363
41364             if (cache.intersections.length) {
41365               limitDelta(graph);
41366             }
41367
41368             for (var i = 0; i < cache.nodes.length; i++) {
41369               var node = graph.entity(cache.nodes[i]);
41370               var start = projection(node.loc);
41371               var end = geoVecAdd(start, _delta);
41372               graph = graph.replace(node.move(projection.invert(end)));
41373             }
41374
41375             if (cache.intersections.length) {
41376               graph = cleanupIntersections(graph);
41377             }
41378
41379             return graph;
41380           };
41381
41382           action.delta = function () {
41383             return _delta;
41384           };
41385
41386           return action;
41387         }
41388
41389         function actionMoveMember(relationId, fromIndex, toIndex) {
41390           return function (graph) {
41391             return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
41392           };
41393         }
41394
41395         function actionMoveNode(nodeID, toLoc) {
41396           var action = function action(graph, t) {
41397             if (t === null || !isFinite(t)) t = 1;
41398             t = Math.min(Math.max(+t, 0), 1);
41399             var node = graph.entity(nodeID);
41400             return graph.replace(node.move(geoVecInterp(node.loc, toLoc, t)));
41401           };
41402
41403           action.transitionable = true;
41404           return action;
41405         }
41406
41407         function actionNoop() {
41408           return function (graph) {
41409             return graph;
41410           };
41411         }
41412
41413         function actionOrthogonalize(wayID, projection, vertexID, degThresh, ep) {
41414           var epsilon = ep || 1e-4;
41415           var threshold = degThresh || 13; // degrees within right or straight to alter
41416           // We test normalized dot products so we can compare as cos(angle)
41417
41418           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
41419           var upperThreshold = Math.cos(threshold * Math.PI / 180);
41420
41421           var action = function action(graph, t) {
41422             if (t === null || !isFinite(t)) t = 1;
41423             t = Math.min(Math.max(+t, 0), 1);
41424             var way = graph.entity(wayID);
41425             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
41426
41427             if (way.tags.nonsquare) {
41428               var tags = Object.assign({}, way.tags); // since we're squaring, remove indication that this is physically unsquare
41429
41430               delete tags.nonsquare;
41431               way = way.update({
41432                 tags: tags
41433               });
41434             }
41435
41436             graph = graph.replace(way);
41437             var isClosed = way.isClosed();
41438             var nodes = graph.childNodes(way).slice(); // shallow copy
41439
41440             if (isClosed) nodes.pop();
41441
41442             if (vertexID !== undefined) {
41443               nodes = nodeSubset(nodes, vertexID, isClosed);
41444               if (nodes.length !== 3) return graph;
41445             } // note: all geometry functions here use the unclosed node/point/coord list
41446
41447
41448             var nodeCount = {};
41449             var points = [];
41450             var corner = {
41451               i: 0,
41452               dotp: 1
41453             };
41454             var node, point, loc, score, motions, i, j;
41455
41456             for (i = 0; i < nodes.length; i++) {
41457               node = nodes[i];
41458               nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
41459               points.push({
41460                 id: node.id,
41461                 coord: projection(node.loc)
41462               });
41463             }
41464
41465             if (points.length === 3) {
41466               // move only one vertex for right triangle
41467               for (i = 0; i < 1000; i++) {
41468                 motions = points.map(calcMotion);
41469                 points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
41470                 score = corner.dotp;
41471
41472                 if (score < epsilon) {
41473                   break;
41474                 }
41475               }
41476
41477               node = graph.entity(nodes[corner.i].id);
41478               loc = projection.invert(points[corner.i].coord);
41479               graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
41480             } else {
41481               var straights = [];
41482               var simplified = []; // Remove points from nearly straight sections..
41483               // This produces a simplified shape to orthogonalize
41484
41485               for (i = 0; i < points.length; i++) {
41486                 point = points[i];
41487                 var dotp = 0;
41488
41489                 if (isClosed || i > 0 && i < points.length - 1) {
41490                   var a = points[(i - 1 + points.length) % points.length];
41491                   var b = points[(i + 1) % points.length];
41492                   dotp = Math.abs(geoOrthoNormalizedDotProduct(a.coord, b.coord, point.coord));
41493                 }
41494
41495                 if (dotp > upperThreshold) {
41496                   straights.push(point);
41497                 } else {
41498                   simplified.push(point);
41499                 }
41500               } // Orthogonalize the simplified shape
41501
41502
41503               var bestPoints = clonePoints(simplified);
41504               var originalPoints = clonePoints(simplified);
41505               score = Infinity;
41506
41507               for (i = 0; i < 1000; i++) {
41508                 motions = simplified.map(calcMotion);
41509
41510                 for (j = 0; j < motions.length; j++) {
41511                   simplified[j].coord = geoVecAdd(simplified[j].coord, motions[j]);
41512                 }
41513
41514                 var newScore = geoOrthoCalcScore(simplified, isClosed, epsilon, threshold);
41515
41516                 if (newScore < score) {
41517                   bestPoints = clonePoints(simplified);
41518                   score = newScore;
41519                 }
41520
41521                 if (score < epsilon) {
41522                   break;
41523                 }
41524               }
41525
41526               var bestCoords = bestPoints.map(function (p) {
41527                 return p.coord;
41528               });
41529               if (isClosed) bestCoords.push(bestCoords[0]); // move the nodes that should move
41530
41531               for (i = 0; i < bestPoints.length; i++) {
41532                 point = bestPoints[i];
41533
41534                 if (!geoVecEqual(originalPoints[i].coord, point.coord)) {
41535                   node = graph.entity(point.id);
41536                   loc = projection.invert(point.coord);
41537                   graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
41538                 }
41539               } // move the nodes along straight segments
41540
41541
41542               for (i = 0; i < straights.length; i++) {
41543                 point = straights[i];
41544                 if (nodeCount[point.id] > 1) continue; // skip self-intersections
41545
41546                 node = graph.entity(point.id);
41547
41548                 if (t === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
41549                   // remove uninteresting points..
41550                   graph = actionDeleteNode(node.id)(graph);
41551                 } else {
41552                   // move interesting points to the nearest edge..
41553                   var choice = geoVecProject(point.coord, bestCoords);
41554
41555                   if (choice) {
41556                     loc = projection.invert(choice.target);
41557                     graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
41558                   }
41559                 }
41560               }
41561             }
41562
41563             return graph;
41564
41565             function clonePoints(array) {
41566               return array.map(function (p) {
41567                 return {
41568                   id: p.id,
41569                   coord: [p.coord[0], p.coord[1]]
41570                 };
41571               });
41572             }
41573
41574             function calcMotion(point, i, array) {
41575               // don't try to move the endpoints of a non-closed way.
41576               if (!isClosed && (i === 0 || i === array.length - 1)) return [0, 0]; // don't try to move a node that appears more than once (self intersection)
41577
41578               if (nodeCount[array[i].id] > 1) return [0, 0];
41579               var a = array[(i - 1 + array.length) % array.length].coord;
41580               var origin = point.coord;
41581               var b = array[(i + 1) % array.length].coord;
41582               var p = geoVecSubtract(a, origin);
41583               var q = geoVecSubtract(b, origin);
41584               var scale = 2 * Math.min(geoVecLength(p), geoVecLength(q));
41585               p = geoVecNormalize(p);
41586               q = geoVecNormalize(q);
41587               var dotp = p[0] * q[0] + p[1] * q[1];
41588               var val = Math.abs(dotp);
41589
41590               if (val < lowerThreshold) {
41591                 // nearly orthogonal
41592                 corner.i = i;
41593                 corner.dotp = val;
41594                 var vec = geoVecNormalize(geoVecAdd(p, q));
41595                 return geoVecScale(vec, 0.1 * dotp * scale);
41596               }
41597
41598               return [0, 0]; // do nothing
41599             }
41600           }; // if we are only orthogonalizing one vertex,
41601           // get that vertex and the previous and next
41602
41603
41604           function nodeSubset(nodes, vertexID, isClosed) {
41605             var first = isClosed ? 0 : 1;
41606             var last = isClosed ? nodes.length : nodes.length - 1;
41607
41608             for (var i = first; i < last; i++) {
41609               if (nodes[i].id === vertexID) {
41610                 return [nodes[(i - 1 + nodes.length) % nodes.length], nodes[i], nodes[(i + 1) % nodes.length]];
41611               }
41612             }
41613
41614             return [];
41615           }
41616
41617           action.disabled = function (graph) {
41618             var way = graph.entity(wayID);
41619             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
41620
41621             graph = graph.replace(way);
41622             var isClosed = way.isClosed();
41623             var nodes = graph.childNodes(way).slice(); // shallow copy
41624
41625             if (isClosed) nodes.pop();
41626             var allowStraightAngles = false;
41627
41628             if (vertexID !== undefined) {
41629               allowStraightAngles = true;
41630               nodes = nodeSubset(nodes, vertexID, isClosed);
41631               if (nodes.length !== 3) return 'end_vertex';
41632             }
41633
41634             var coords = nodes.map(function (n) {
41635               return projection(n.loc);
41636             });
41637             var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles);
41638
41639             if (score === null) {
41640               return 'not_squarish';
41641             } else if (score === 0) {
41642               return 'square_enough';
41643             } else {
41644               return false;
41645             }
41646           };
41647
41648           action.transitionable = true;
41649           return action;
41650         }
41651
41652         //
41653         // `turn` must be an `osmTurn` object
41654         // see osm/intersection.js, pathToTurn()
41655         //
41656         // This specifies a restriction of type `restriction` when traveling from
41657         // `turn.from.way` toward `turn.to.way` via `turn.via.node` OR `turn.via.ways`.
41658         // (The action does not check that these entities form a valid intersection.)
41659         //
41660         // From, to, and via ways should be split before calling this action.
41661         // (old versions of the code would split the ways here, but we no longer do it)
41662         //
41663         // For testing convenience, accepts a restrictionID to assign to the new
41664         // relation. Normally, this will be undefined and the relation will
41665         // automatically be assigned a new ID.
41666         //
41667
41668         function actionRestrictTurn(turn, restrictionType, restrictionID) {
41669           return function (graph) {
41670             var fromWay = graph.entity(turn.from.way);
41671             var toWay = graph.entity(turn.to.way);
41672             var viaNode = turn.via.node && graph.entity(turn.via.node);
41673             var viaWays = turn.via.ways && turn.via.ways.map(function (id) {
41674               return graph.entity(id);
41675             });
41676             var members = [];
41677             members.push({
41678               id: fromWay.id,
41679               type: 'way',
41680               role: 'from'
41681             });
41682
41683             if (viaNode) {
41684               members.push({
41685                 id: viaNode.id,
41686                 type: 'node',
41687                 role: 'via'
41688               });
41689             } else if (viaWays) {
41690               viaWays.forEach(function (viaWay) {
41691                 members.push({
41692                   id: viaWay.id,
41693                   type: 'way',
41694                   role: 'via'
41695                 });
41696               });
41697             }
41698
41699             members.push({
41700               id: toWay.id,
41701               type: 'way',
41702               role: 'to'
41703             });
41704             return graph.replace(osmRelation({
41705               id: restrictionID,
41706               tags: {
41707                 type: 'restriction',
41708                 restriction: restrictionType
41709               },
41710               members: members
41711             }));
41712           };
41713         }
41714
41715         function actionRevert(id) {
41716           var action = function action(graph) {
41717             var entity = graph.hasEntity(id),
41718                 base = graph.base().entities[id];
41719
41720             if (entity && !base) {
41721               // entity will be removed..
41722               if (entity.type === 'node') {
41723                 graph.parentWays(entity).forEach(function (parent) {
41724                   parent = parent.removeNode(id);
41725                   graph = graph.replace(parent);
41726
41727                   if (parent.isDegenerate()) {
41728                     graph = actionDeleteWay(parent.id)(graph);
41729                   }
41730                 });
41731               }
41732
41733               graph.parentRelations(entity).forEach(function (parent) {
41734                 parent = parent.removeMembersWithID(id);
41735                 graph = graph.replace(parent);
41736
41737                 if (parent.isDegenerate()) {
41738                   graph = actionDeleteRelation(parent.id)(graph);
41739                 }
41740               });
41741             }
41742
41743             return graph.revert(id);
41744           };
41745
41746           return action;
41747         }
41748
41749         function actionRotate(rotateIds, pivot, angle, projection) {
41750           var action = function action(graph) {
41751             return graph.update(function (graph) {
41752               utilGetAllNodes(rotateIds, graph).forEach(function (node) {
41753                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
41754                 graph = graph.replace(node.move(projection.invert(point)));
41755               });
41756             });
41757           };
41758
41759           return action;
41760         }
41761
41762         function actionScale(ids, pivotLoc, scaleFactor, projection) {
41763           return function (graph) {
41764             return graph.update(function (graph) {
41765               var point, radial;
41766               utilGetAllNodes(ids, graph).forEach(function (node) {
41767                 point = projection(node.loc);
41768                 radial = [point[0] - pivotLoc[0], point[1] - pivotLoc[1]];
41769                 point = [pivotLoc[0] + scaleFactor * radial[0], pivotLoc[1] + scaleFactor * radial[1]];
41770                 graph = graph.replace(node.move(projection.invert(point)));
41771               });
41772             });
41773           };
41774         }
41775
41776         /* Align nodes along their common axis */
41777
41778         function actionStraightenNodes(nodeIDs, projection) {
41779           function positionAlongWay(a, o, b) {
41780             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
41781           } // returns the endpoints of the long axis of symmetry of the `points` bounding rect
41782
41783
41784           function getEndpoints(points) {
41785             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
41786             // The shape's surrounding rectangle has 2 axes of symmetry.
41787             // Snap points to the long axis
41788
41789             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
41790             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
41791             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
41792             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
41793             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
41794
41795             if (isLong) {
41796               return [p1, q1];
41797             }
41798
41799             return [p2, q2];
41800           }
41801
41802           var action = function action(graph, t) {
41803             if (t === null || !isFinite(t)) t = 1;
41804             t = Math.min(Math.max(+t, 0), 1);
41805             var nodes = nodeIDs.map(function (id) {
41806               return graph.entity(id);
41807             });
41808             var points = nodes.map(function (n) {
41809               return projection(n.loc);
41810             });
41811             var endpoints = getEndpoints(points);
41812             var startPoint = endpoints[0];
41813             var endPoint = endpoints[1]; // Move points onto the line connecting the endpoints
41814
41815             for (var i = 0; i < points.length; i++) {
41816               var node = nodes[i];
41817               var point = points[i];
41818               var u = positionAlongWay(point, startPoint, endPoint);
41819               var point2 = geoVecInterp(startPoint, endPoint, u);
41820               var loc2 = projection.invert(point2);
41821               graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
41822             }
41823
41824             return graph;
41825           };
41826
41827           action.disabled = function (graph) {
41828             var nodes = nodeIDs.map(function (id) {
41829               return graph.entity(id);
41830             });
41831             var points = nodes.map(function (n) {
41832               return projection(n.loc);
41833             });
41834             var endpoints = getEndpoints(points);
41835             var startPoint = endpoints[0];
41836             var endPoint = endpoints[1];
41837             var maxDistance = 0;
41838
41839             for (var i = 0; i < points.length; i++) {
41840               var point = points[i];
41841               var u = positionAlongWay(point, startPoint, endPoint);
41842               var p = geoVecInterp(startPoint, endPoint, u);
41843               var dist = geoVecLength(p, point);
41844
41845               if (!isNaN(dist) && dist > maxDistance) {
41846                 maxDistance = dist;
41847               }
41848             }
41849
41850             if (maxDistance < 0.0001) {
41851               return 'straight_enough';
41852             }
41853           };
41854
41855           action.transitionable = true;
41856           return action;
41857         }
41858
41859         /*
41860          * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
41861          */
41862
41863         function actionStraightenWay(selectedIDs, projection) {
41864           function positionAlongWay(a, o, b) {
41865             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
41866           } // Return all selected ways as a continuous, ordered array of nodes
41867
41868
41869           function allNodes(graph) {
41870             var nodes = [];
41871             var startNodes = [];
41872             var endNodes = [];
41873             var remainingWays = [];
41874             var selectedWays = selectedIDs.filter(function (w) {
41875               return graph.entity(w).type === 'way';
41876             });
41877             var selectedNodes = selectedIDs.filter(function (n) {
41878               return graph.entity(n).type === 'node';
41879             });
41880
41881             for (var i = 0; i < selectedWays.length; i++) {
41882               var way = graph.entity(selectedWays[i]);
41883               nodes = way.nodes.slice(0);
41884               remainingWays.push(nodes);
41885               startNodes.push(nodes[0]);
41886               endNodes.push(nodes[nodes.length - 1]);
41887             } // Remove duplicate end/startNodes (duplicate nodes cannot be at the line end,
41888             //   and need to be removed so currNode difference calculation below works)
41889             // i.e. ["n-1", "n-1", "n-2"] => ["n-2"]
41890
41891
41892             startNodes = startNodes.filter(function (n) {
41893               return startNodes.indexOf(n) === startNodes.lastIndexOf(n);
41894             });
41895             endNodes = endNodes.filter(function (n) {
41896               return endNodes.indexOf(n) === endNodes.lastIndexOf(n);
41897             }); // Choose the initial endpoint to start from
41898
41899             var currNode = utilArrayDifference(startNodes, endNodes).concat(utilArrayDifference(endNodes, startNodes))[0];
41900             var nextWay = [];
41901             nodes = []; // Create nested function outside of loop to avoid "function in loop" lint error
41902
41903             var getNextWay = function getNextWay(currNode, remainingWays) {
41904               return remainingWays.filter(function (way) {
41905                 return way[0] === currNode || way[way.length - 1] === currNode;
41906               })[0];
41907             }; // Add nodes to end of nodes array, until all ways are added
41908
41909
41910             while (remainingWays.length) {
41911               nextWay = getNextWay(currNode, remainingWays);
41912               remainingWays = utilArrayDifference(remainingWays, [nextWay]);
41913
41914               if (nextWay[0] !== currNode) {
41915                 nextWay.reverse();
41916               }
41917
41918               nodes = nodes.concat(nextWay);
41919               currNode = nodes[nodes.length - 1];
41920             } // If user selected 2 nodes to straighten between, then slice nodes array to those nodes
41921
41922
41923             if (selectedNodes.length === 2) {
41924               var startNodeIdx = nodes.indexOf(selectedNodes[0]);
41925               var endNodeIdx = nodes.indexOf(selectedNodes[1]);
41926               var sortedStartEnd = [startNodeIdx, endNodeIdx];
41927               sortedStartEnd.sort(function (a, b) {
41928                 return a - b;
41929               });
41930               nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
41931             }
41932
41933             return nodes.map(function (n) {
41934               return graph.entity(n);
41935             });
41936           }
41937
41938           function shouldKeepNode(node, graph) {
41939             return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
41940           }
41941
41942           var action = function action(graph, t) {
41943             if (t === null || !isFinite(t)) t = 1;
41944             t = Math.min(Math.max(+t, 0), 1);
41945             var nodes = allNodes(graph);
41946             var points = nodes.map(function (n) {
41947               return projection(n.loc);
41948             });
41949             var startPoint = points[0];
41950             var endPoint = points[points.length - 1];
41951             var toDelete = [];
41952             var i;
41953
41954             for (i = 1; i < points.length - 1; i++) {
41955               var node = nodes[i];
41956               var point = points[i];
41957
41958               if (t < 1 || shouldKeepNode(node, graph)) {
41959                 var u = positionAlongWay(point, startPoint, endPoint);
41960                 var p = geoVecInterp(startPoint, endPoint, u);
41961                 var loc2 = projection.invert(p);
41962                 graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
41963               } else {
41964                 // safe to delete
41965                 if (toDelete.indexOf(node) === -1) {
41966                   toDelete.push(node);
41967                 }
41968               }
41969             }
41970
41971             for (i = 0; i < toDelete.length; i++) {
41972               graph = actionDeleteNode(toDelete[i].id)(graph);
41973             }
41974
41975             return graph;
41976           };
41977
41978           action.disabled = function (graph) {
41979             // check way isn't too bendy
41980             var nodes = allNodes(graph);
41981             var points = nodes.map(function (n) {
41982               return projection(n.loc);
41983             });
41984             var startPoint = points[0];
41985             var endPoint = points[points.length - 1];
41986             var threshold = 0.2 * geoVecLength(startPoint, endPoint);
41987             var i;
41988
41989             if (threshold === 0) {
41990               return 'too_bendy';
41991             }
41992
41993             var maxDistance = 0;
41994
41995             for (i = 1; i < points.length - 1; i++) {
41996               var point = points[i];
41997               var u = positionAlongWay(point, startPoint, endPoint);
41998               var p = geoVecInterp(startPoint, endPoint, u);
41999               var dist = geoVecLength(p, point); // to bendy if point is off by 20% of total start/end distance in projected space
42000
42001               if (isNaN(dist) || dist > threshold) {
42002                 return 'too_bendy';
42003               } else if (dist > maxDistance) {
42004                 maxDistance = dist;
42005               }
42006             }
42007
42008             var keepingAllNodes = nodes.every(function (node, i) {
42009               return i === 0 || i === nodes.length - 1 || shouldKeepNode(node, graph);
42010             });
42011
42012             if (maxDistance < 0.0001 && // Allow straightening even if already straight in order to remove extraneous nodes
42013             keepingAllNodes) {
42014               return 'straight_enough';
42015             }
42016           };
42017
42018           action.transitionable = true;
42019           return action;
42020         }
42021
42022         //
42023         // `turn` must be an `osmTurn` object with a `restrictionID` property.
42024         // see osm/intersection.js, pathToTurn()
42025         //
42026
42027         function actionUnrestrictTurn(turn) {
42028           return function (graph) {
42029             return actionDeleteRelation(turn.restrictionID)(graph);
42030           };
42031         }
42032
42033         /* Reflect the given area around its axis of symmetry */
42034
42035         function actionReflect(reflectIds, projection) {
42036           var _useLongAxis = true;
42037
42038           var action = function action(graph, t) {
42039             if (t === null || !isFinite(t)) t = 1;
42040             t = Math.min(Math.max(+t, 0), 1);
42041             var nodes = utilGetAllNodes(reflectIds, graph);
42042             var points = nodes.map(function (n) {
42043               return projection(n.loc);
42044             });
42045             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
42046             // The shape's surrounding rectangle has 2 axes of symmetry.
42047             // Reflect across the longer axis by default.
42048
42049             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
42050             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
42051             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
42052             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
42053             var p, q;
42054             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
42055
42056             if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
42057               p = p1;
42058               q = q1;
42059             } else {
42060               p = p2;
42061               q = q2;
42062             } // reflect c across pq
42063             // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
42064
42065
42066             var dx = q[0] - p[0];
42067             var dy = q[1] - p[1];
42068             var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
42069             var b = 2 * dx * dy / (dx * dx + dy * dy);
42070
42071             for (var i = 0; i < nodes.length; i++) {
42072               var node = nodes[i];
42073               var c = projection(node.loc);
42074               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]];
42075               var loc2 = projection.invert(c2);
42076               node = node.move(geoVecInterp(node.loc, loc2, t));
42077               graph = graph.replace(node);
42078             }
42079
42080             return graph;
42081           };
42082
42083           action.useLongAxis = function (val) {
42084             if (!arguments.length) return _useLongAxis;
42085             _useLongAxis = val;
42086             return action;
42087           };
42088
42089           action.transitionable = true;
42090           return action;
42091         }
42092
42093         function actionUpgradeTags(entityId, oldTags, replaceTags) {
42094           return function (graph) {
42095             var entity = graph.entity(entityId);
42096             var tags = Object.assign({}, entity.tags); // shallow copy
42097
42098             var transferValue;
42099             var semiIndex;
42100
42101             for (var oldTagKey in oldTags) {
42102               if (!(oldTagKey in tags)) continue; // wildcard match
42103
42104               if (oldTags[oldTagKey] === '*') {
42105                 // note the value since we might need to transfer it
42106                 transferValue = tags[oldTagKey];
42107                 delete tags[oldTagKey]; // exact match
42108               } else if (oldTags[oldTagKey] === tags[oldTagKey]) {
42109                 delete tags[oldTagKey]; // match is within semicolon-delimited values
42110               } else {
42111                 var vals = tags[oldTagKey].split(';').filter(Boolean);
42112                 var oldIndex = vals.indexOf(oldTags[oldTagKey]);
42113
42114                 if (vals.length === 1 || oldIndex === -1) {
42115                   delete tags[oldTagKey];
42116                 } else {
42117                   if (replaceTags && replaceTags[oldTagKey]) {
42118                     // replacing a value within a semicolon-delimited value, note the index
42119                     semiIndex = oldIndex;
42120                   }
42121
42122                   vals.splice(oldIndex, 1);
42123                   tags[oldTagKey] = vals.join(';');
42124                 }
42125               }
42126             }
42127
42128             if (replaceTags) {
42129               for (var replaceKey in replaceTags) {
42130                 var replaceValue = replaceTags[replaceKey];
42131
42132                 if (replaceValue === '*') {
42133                   if (tags[replaceKey] && tags[replaceKey] !== 'no') {
42134                     // allow any pre-existing value except `no` (troll tag)
42135                     continue;
42136                   } else {
42137                     // otherwise assume `yes` is okay
42138                     tags[replaceKey] = 'yes';
42139                   }
42140                 } else if (replaceValue === '$1') {
42141                   tags[replaceKey] = transferValue;
42142                 } else {
42143                   if (tags[replaceKey] && oldTags[replaceKey] && semiIndex !== undefined) {
42144                     // don't override preexisting values
42145                     var existingVals = tags[replaceKey].split(';').filter(Boolean);
42146
42147                     if (existingVals.indexOf(replaceValue) === -1) {
42148                       existingVals.splice(semiIndex, 0, replaceValue);
42149                       tags[replaceKey] = existingVals.join(';');
42150                     }
42151                   } else {
42152                     tags[replaceKey] = replaceValue;
42153                   }
42154                 }
42155               }
42156             }
42157
42158             return graph.replace(entity.update({
42159               tags: tags
42160             }));
42161           };
42162         }
42163
42164         function behaviorEdit(context) {
42165           function behavior() {
42166             context.map().minzoom(context.minEditableZoom());
42167           }
42168
42169           behavior.off = function () {
42170             context.map().minzoom(0);
42171           };
42172
42173           return behavior;
42174         }
42175
42176         /*
42177            The hover behavior adds the `.hover` class on pointerover to all elements to which
42178            the identical datum is bound, and removes it on pointerout.
42179
42180            The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
42181            representation may consist of several elements scattered throughout the DOM hierarchy.
42182            Only one of these elements can have the :hover pseudo-class, but all of them will
42183            have the .hover class.
42184          */
42185
42186         function behaviorHover(context) {
42187           var dispatch = dispatch$8('hover');
42188
42189           var _selection = select(null);
42190
42191           var _newNodeId = null;
42192           var _initialNodeID = null;
42193
42194           var _altDisables;
42195
42196           var _ignoreVertex;
42197
42198           var _targets = []; // use pointer events on supported platforms; fallback to mouse events
42199
42200           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
42201
42202           function keydown(d3_event) {
42203             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
42204               _selection.selectAll('.hover').classed('hover-suppressed', true).classed('hover', false);
42205
42206               _selection.classed('hover-disabled', true);
42207
42208               dispatch.call('hover', this, null);
42209             }
42210           }
42211
42212           function keyup(d3_event) {
42213             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
42214               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false).classed('hover', true);
42215
42216               _selection.classed('hover-disabled', false);
42217
42218               dispatch.call('hover', this, _targets);
42219             }
42220           }
42221
42222           function behavior(selection) {
42223             _selection = selection;
42224             _targets = [];
42225
42226             if (_initialNodeID) {
42227               _newNodeId = _initialNodeID;
42228               _initialNodeID = null;
42229             } else {
42230               _newNodeId = null;
42231             }
42232
42233             _selection.on(_pointerPrefix + 'over.hover', pointerover).on(_pointerPrefix + 'out.hover', pointerout) // treat pointerdown as pointerover for touch devices
42234             .on(_pointerPrefix + 'down.hover', pointerover);
42235
42236             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', pointerout, true).on('keydown.hover', keydown).on('keyup.hover', keyup);
42237
42238             function eventTarget(d3_event) {
42239               var datum = d3_event.target && d3_event.target.__data__;
42240               if (_typeof(datum) !== 'object') return null;
42241
42242               if (!(datum instanceof osmEntity) && datum.properties && datum.properties.entity instanceof osmEntity) {
42243                 return datum.properties.entity;
42244               }
42245
42246               return datum;
42247             }
42248
42249             function pointerover(d3_event) {
42250               // ignore mouse hovers with buttons pressed unless dragging
42251               if (context.mode().id.indexOf('drag') === -1 && (!d3_event.pointerType || d3_event.pointerType === 'mouse') && d3_event.buttons) return;
42252               var target = eventTarget(d3_event);
42253
42254               if (target && _targets.indexOf(target) === -1) {
42255                 _targets.push(target);
42256
42257                 updateHover(d3_event, _targets);
42258               }
42259             }
42260
42261             function pointerout(d3_event) {
42262               var target = eventTarget(d3_event);
42263
42264               var index = _targets.indexOf(target);
42265
42266               if (index !== -1) {
42267                 _targets.splice(index);
42268
42269                 updateHover(d3_event, _targets);
42270               }
42271             }
42272
42273             function allowsVertex(d) {
42274               return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
42275             }
42276
42277             function modeAllowsHover(target) {
42278               var mode = context.mode();
42279
42280               if (mode.id === 'add-point') {
42281                 return mode.preset.matchGeometry('vertex') || target.type !== 'way' && target.geometry(context.graph()) !== 'vertex';
42282               }
42283
42284               return true;
42285             }
42286
42287             function updateHover(d3_event, targets) {
42288               _selection.selectAll('.hover').classed('hover', false);
42289
42290               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
42291
42292               var mode = context.mode();
42293
42294               if (!_newNodeId && (mode.id === 'draw-line' || mode.id === 'draw-area')) {
42295                 var node = targets.find(function (target) {
42296                   return target instanceof osmEntity && target.type === 'node';
42297                 });
42298                 _newNodeId = node && node.id;
42299               }
42300
42301               targets = targets.filter(function (datum) {
42302                 if (datum instanceof osmEntity) {
42303                   // If drawing a way, don't hover on a node that was just placed. #3974
42304                   return datum.id !== _newNodeId && (datum.type !== 'node' || !_ignoreVertex || allowsVertex(datum)) && modeAllowsHover(datum);
42305                 }
42306
42307                 return true;
42308               });
42309               var selector = '';
42310
42311               for (var i in targets) {
42312                 var datum = targets[i]; // What are we hovering over?
42313
42314                 if (datum.__featurehash__) {
42315                   // hovering custom data
42316                   selector += ', .data' + datum.__featurehash__;
42317                 } else if (datum instanceof QAItem) {
42318                   selector += ', .' + datum.service + '.itemId-' + datum.id;
42319                 } else if (datum instanceof osmNote) {
42320                   selector += ', .note-' + datum.id;
42321                 } else if (datum instanceof osmEntity) {
42322                   selector += ', .' + datum.id;
42323
42324                   if (datum.type === 'relation') {
42325                     for (var j in datum.members) {
42326                       selector += ', .' + datum.members[j].id;
42327                     }
42328                   }
42329                 }
42330               }
42331
42332               var suppressed = _altDisables && d3_event && d3_event.altKey;
42333
42334               if (selector.trim().length) {
42335                 // remove the first comma
42336                 selector = selector.slice(1);
42337
42338                 _selection.selectAll(selector).classed(suppressed ? 'hover-suppressed' : 'hover', true);
42339               }
42340
42341               dispatch.call('hover', this, !suppressed && targets);
42342             }
42343           }
42344
42345           behavior.off = function (selection) {
42346             selection.selectAll('.hover').classed('hover', false);
42347             selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
42348             selection.classed('hover-disabled', false);
42349             selection.on(_pointerPrefix + 'over.hover', null).on(_pointerPrefix + 'out.hover', null).on(_pointerPrefix + 'down.hover', null);
42350             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', null, true).on('keydown.hover', null).on('keyup.hover', null);
42351           };
42352
42353           behavior.altDisables = function (val) {
42354             if (!arguments.length) return _altDisables;
42355             _altDisables = val;
42356             return behavior;
42357           };
42358
42359           behavior.ignoreVertex = function (val) {
42360             if (!arguments.length) return _ignoreVertex;
42361             _ignoreVertex = val;
42362             return behavior;
42363           };
42364
42365           behavior.initialNodeID = function (nodeId) {
42366             _initialNodeID = nodeId;
42367             return behavior;
42368           };
42369
42370           return utilRebind(behavior, dispatch, 'on');
42371         }
42372
42373         var _disableSpace = false;
42374         var _lastSpace = null;
42375         function behaviorDraw(context) {
42376           var dispatch = dispatch$8('move', 'down', 'downcancel', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish');
42377           var keybinding = utilKeybinding('draw');
42378
42379           var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true).on('hover', context.ui().sidebar.hover);
42380
42381           var _edit = behaviorEdit(context);
42382
42383           var _closeTolerance = 4;
42384           var _tolerance = 12;
42385           var _mouseLeave = false;
42386           var _lastMouse = null;
42387
42388           var _lastPointerUpEvent;
42389
42390           var _downPointer; // use pointer events on supported platforms; fallback to mouse events
42391
42392
42393           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // related code
42394           // - `mode/drag_node.js` `datum()`
42395
42396
42397           function datum(d3_event) {
42398             var mode = context.mode();
42399             var isNote = mode && mode.id.indexOf('note') !== -1;
42400             if (d3_event.altKey || isNote) return {};
42401             var element;
42402
42403             if (d3_event.type === 'keydown') {
42404               element = _lastMouse && _lastMouse.target;
42405             } else {
42406               element = d3_event.target;
42407             } // When drawing, snap only to touch targets..
42408             // (this excludes area fills and active drawing elements)
42409
42410
42411             var d = element.__data__;
42412             return d && d.properties && d.properties.target ? d : {};
42413           }
42414
42415           function pointerdown(d3_event) {
42416             if (_downPointer) return;
42417             var pointerLocGetter = utilFastMouse(this);
42418             _downPointer = {
42419               id: d3_event.pointerId || 'mouse',
42420               pointerLocGetter: pointerLocGetter,
42421               downTime: +new Date(),
42422               downLoc: pointerLocGetter(d3_event)
42423             };
42424             dispatch.call('down', this, d3_event, datum(d3_event));
42425           }
42426
42427           function pointerup(d3_event) {
42428             if (!_downPointer || _downPointer.id !== (d3_event.pointerId || 'mouse')) return;
42429             var downPointer = _downPointer;
42430             _downPointer = null;
42431             _lastPointerUpEvent = d3_event;
42432             if (downPointer.isCancelled) return;
42433             var t2 = +new Date();
42434             var p2 = downPointer.pointerLocGetter(d3_event);
42435             var dist = geoVecLength(downPointer.downLoc, p2);
42436
42437             if (dist < _closeTolerance || dist < _tolerance && t2 - downPointer.downTime < 500) {
42438               // Prevent a quick second click
42439               select(window).on('click.draw-block', function () {
42440                 d3_event.stopPropagation();
42441               }, true);
42442               context.map().dblclickZoomEnable(false);
42443               window.setTimeout(function () {
42444                 context.map().dblclickZoomEnable(true);
42445                 select(window).on('click.draw-block', null);
42446               }, 500);
42447               click(d3_event, p2);
42448             }
42449           }
42450
42451           function pointermove(d3_event) {
42452             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse') && !_downPointer.isCancelled) {
42453               var p2 = _downPointer.pointerLocGetter(d3_event);
42454
42455               var dist = geoVecLength(_downPointer.downLoc, p2);
42456
42457               if (dist >= _closeTolerance) {
42458                 _downPointer.isCancelled = true;
42459                 dispatch.call('downcancel', this);
42460               }
42461             }
42462
42463             if (d3_event.pointerType && d3_event.pointerType !== 'mouse' || d3_event.buttons || _downPointer) return; // HACK: Mobile Safari likes to send one or more `mouse` type pointermove
42464             // events immediately after non-mouse pointerup events; detect and ignore them.
42465
42466             if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== 'mouse' && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
42467             _lastMouse = d3_event;
42468             dispatch.call('move', this, d3_event, datum(d3_event));
42469           }
42470
42471           function pointercancel(d3_event) {
42472             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse')) {
42473               if (!_downPointer.isCancelled) {
42474                 dispatch.call('downcancel', this);
42475               }
42476
42477               _downPointer = null;
42478             }
42479           }
42480
42481           function mouseenter() {
42482             _mouseLeave = false;
42483           }
42484
42485           function mouseleave() {
42486             _mouseLeave = true;
42487           }
42488
42489           function allowsVertex(d) {
42490             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
42491           } // related code
42492           // - `mode/drag_node.js`     `doMove()`
42493           // - `behavior/draw.js`      `click()`
42494           // - `behavior/draw_way.js`  `move()`
42495
42496
42497           function click(d3_event, loc) {
42498             var d = datum(d3_event);
42499             var target = d && d.properties && d.properties.entity;
42500             var mode = context.mode();
42501
42502             if (target && target.type === 'node' && allowsVertex(target)) {
42503               // Snap to a node
42504               dispatch.call('clickNode', this, target, d);
42505               return;
42506             } else if (target && target.type === 'way' && (mode.id !== 'add-point' || mode.preset.matchGeometry('vertex'))) {
42507               // Snap to a way
42508               var choice = geoChooseEdge(context.graph().childNodes(target), loc, context.projection, context.activeID());
42509
42510               if (choice) {
42511                 var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]];
42512                 dispatch.call('clickWay', this, choice.loc, edge, d);
42513                 return;
42514               }
42515             } else if (mode.id !== 'add-point' || mode.preset.matchGeometry('point')) {
42516               var locLatLng = context.projection.invert(loc);
42517               dispatch.call('click', this, locLatLng, d);
42518             }
42519           } // treat a spacebar press like a click
42520
42521
42522           function space(d3_event) {
42523             d3_event.preventDefault();
42524             d3_event.stopPropagation();
42525             var currSpace = context.map().mouse();
42526
42527             if (_disableSpace && _lastSpace) {
42528               var dist = geoVecLength(_lastSpace, currSpace);
42529
42530               if (dist > _tolerance) {
42531                 _disableSpace = false;
42532               }
42533             }
42534
42535             if (_disableSpace || _mouseLeave || !_lastMouse) return; // user must move mouse or release space bar to allow another click
42536
42537             _lastSpace = currSpace;
42538             _disableSpace = true;
42539             select(window).on('keyup.space-block', function () {
42540               d3_event.preventDefault();
42541               d3_event.stopPropagation();
42542               _disableSpace = false;
42543               select(window).on('keyup.space-block', null);
42544             }); // get the current mouse position
42545
42546             var loc = context.map().mouse() || // or the map center if the mouse has never entered the map
42547             context.projection(context.map().center());
42548             click(d3_event, loc);
42549           }
42550
42551           function backspace(d3_event) {
42552             d3_event.preventDefault();
42553             dispatch.call('undo');
42554           }
42555
42556           function del(d3_event) {
42557             d3_event.preventDefault();
42558             dispatch.call('cancel');
42559           }
42560
42561           function ret(d3_event) {
42562             d3_event.preventDefault();
42563             dispatch.call('finish');
42564           }
42565
42566           function behavior(selection) {
42567             context.install(_hover);
42568             context.install(_edit);
42569             _downPointer = null;
42570             keybinding.on('⌫', backspace).on('⌦', del).on('⎋', ret).on('↩', ret).on('space', space).on('⌥space', space);
42571             selection.on('mouseenter.draw', mouseenter).on('mouseleave.draw', mouseleave).on(_pointerPrefix + 'down.draw', pointerdown).on(_pointerPrefix + 'move.draw', pointermove);
42572             select(window).on(_pointerPrefix + 'up.draw', pointerup, true).on('pointercancel.draw', pointercancel, true);
42573             select(document).call(keybinding);
42574             return behavior;
42575           }
42576
42577           behavior.off = function (selection) {
42578             context.ui().sidebar.hover.cancel();
42579             context.uninstall(_hover);
42580             context.uninstall(_edit);
42581             selection.on('mouseenter.draw', null).on('mouseleave.draw', null).on(_pointerPrefix + 'down.draw', null).on(_pointerPrefix + 'move.draw', null);
42582             select(window).on(_pointerPrefix + 'up.draw', null).on('pointercancel.draw', null); // note: keyup.space-block, click.draw-block should remain
42583
42584             select(document).call(keybinding.unbind);
42585           };
42586
42587           behavior.hover = function () {
42588             return _hover;
42589           };
42590
42591           return utilRebind(behavior, dispatch, 'on');
42592         }
42593
42594         function initRange(domain, range) {
42595           switch (arguments.length) {
42596             case 0:
42597               break;
42598
42599             case 1:
42600               this.range(domain);
42601               break;
42602
42603             default:
42604               this.range(range).domain(domain);
42605               break;
42606           }
42607
42608           return this;
42609         }
42610
42611         function constants(x) {
42612           return function () {
42613             return x;
42614           };
42615         }
42616
42617         function number(x) {
42618           return +x;
42619         }
42620
42621         var unit = [0, 1];
42622         function identity$1(x) {
42623           return x;
42624         }
42625
42626         function normalize(a, b) {
42627           return (b -= a = +a) ? function (x) {
42628             return (x - a) / b;
42629           } : constants(isNaN(b) ? NaN : 0.5);
42630         }
42631
42632         function clamper(a, b) {
42633           var t;
42634           if (a > b) t = a, a = b, b = t;
42635           return function (x) {
42636             return Math.max(a, Math.min(b, x));
42637           };
42638         } // normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
42639         // interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].
42640
42641
42642         function bimap(domain, range, interpolate) {
42643           var d0 = domain[0],
42644               d1 = domain[1],
42645               r0 = range[0],
42646               r1 = range[1];
42647           if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
42648           return function (x) {
42649             return r0(d0(x));
42650           };
42651         }
42652
42653         function polymap(domain, range, interpolate) {
42654           var j = Math.min(domain.length, range.length) - 1,
42655               d = new Array(j),
42656               r = new Array(j),
42657               i = -1; // Reverse descending domains.
42658
42659           if (domain[j] < domain[0]) {
42660             domain = domain.slice().reverse();
42661             range = range.slice().reverse();
42662           }
42663
42664           while (++i < j) {
42665             d[i] = normalize(domain[i], domain[i + 1]);
42666             r[i] = interpolate(range[i], range[i + 1]);
42667           }
42668
42669           return function (x) {
42670             var i = bisectRight(domain, x, 1, j) - 1;
42671             return r[i](d[i](x));
42672           };
42673         }
42674
42675         function copy$1(source, target) {
42676           return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
42677         }
42678         function transformer() {
42679           var domain = unit,
42680               range = unit,
42681               interpolate = interpolate$1,
42682               transform,
42683               untransform,
42684               unknown,
42685               clamp = identity$1,
42686               piecewise,
42687               output,
42688               input;
42689
42690           function rescale() {
42691             var n = Math.min(domain.length, range.length);
42692             if (clamp !== identity$1) clamp = clamper(domain[0], domain[n - 1]);
42693             piecewise = n > 2 ? polymap : bimap;
42694             output = input = null;
42695             return scale;
42696           }
42697
42698           function scale(x) {
42699             return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));
42700           }
42701
42702           scale.invert = function (y) {
42703             return clamp(untransform((input || (input = piecewise(range, domain.map(transform), d3_interpolateNumber)))(y)));
42704           };
42705
42706           scale.domain = function (_) {
42707             return arguments.length ? (domain = Array.from(_, number), rescale()) : domain.slice();
42708           };
42709
42710           scale.range = function (_) {
42711             return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
42712           };
42713
42714           scale.rangeRound = function (_) {
42715             return range = Array.from(_), interpolate = interpolateRound, rescale();
42716           };
42717
42718           scale.clamp = function (_) {
42719             return arguments.length ? (clamp = _ ? true : identity$1, rescale()) : clamp !== identity$1;
42720           };
42721
42722           scale.interpolate = function (_) {
42723             return arguments.length ? (interpolate = _, rescale()) : interpolate;
42724           };
42725
42726           scale.unknown = function (_) {
42727             return arguments.length ? (unknown = _, scale) : unknown;
42728           };
42729
42730           return function (t, u) {
42731             transform = t, untransform = u;
42732             return rescale();
42733           };
42734         }
42735         function continuous() {
42736           return transformer()(identity$1, identity$1);
42737         }
42738
42739         function formatDecimal (x) {
42740           return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
42741         } // Computes the decimal coefficient and exponent of the specified number x with
42742         // significant digits p, where x is positive and p is in [1, 21] or undefined.
42743         // For example, formatDecimalParts(1.23) returns ["123", 0].
42744
42745         function formatDecimalParts(x, p) {
42746           if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
42747
42748           var i,
42749               coefficient = x.slice(0, i); // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
42750           // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
42751
42752           return [coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +x.slice(i + 1)];
42753         }
42754
42755         function exponent (x) {
42756           return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
42757         }
42758
42759         function formatGroup (grouping, thousands) {
42760           return function (value, width) {
42761             var i = value.length,
42762                 t = [],
42763                 j = 0,
42764                 g = grouping[0],
42765                 length = 0;
42766
42767             while (i > 0 && g > 0) {
42768               if (length + g + 1 > width) g = Math.max(1, width - length);
42769               t.push(value.substring(i -= g, i + g));
42770               if ((length += g + 1) > width) break;
42771               g = grouping[j = (j + 1) % grouping.length];
42772             }
42773
42774             return t.reverse().join(thousands);
42775           };
42776         }
42777
42778         function formatNumerals (numerals) {
42779           return function (value) {
42780             return value.replace(/[0-9]/g, function (i) {
42781               return numerals[+i];
42782             });
42783           };
42784         }
42785
42786         // [[fill]align][sign][symbol][0][width][,][.precision][~][type]
42787         var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
42788         function formatSpecifier(specifier) {
42789           if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
42790           var match;
42791           return new FormatSpecifier({
42792             fill: match[1],
42793             align: match[2],
42794             sign: match[3],
42795             symbol: match[4],
42796             zero: match[5],
42797             width: match[6],
42798             comma: match[7],
42799             precision: match[8] && match[8].slice(1),
42800             trim: match[9],
42801             type: match[10]
42802           });
42803         }
42804         formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
42805
42806         function FormatSpecifier(specifier) {
42807           this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
42808           this.align = specifier.align === undefined ? ">" : specifier.align + "";
42809           this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
42810           this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
42811           this.zero = !!specifier.zero;
42812           this.width = specifier.width === undefined ? undefined : +specifier.width;
42813           this.comma = !!specifier.comma;
42814           this.precision = specifier.precision === undefined ? undefined : +specifier.precision;
42815           this.trim = !!specifier.trim;
42816           this.type = specifier.type === undefined ? "" : specifier.type + "";
42817         }
42818
42819         FormatSpecifier.prototype.toString = function () {
42820           return this.fill + this.align + this.sign + this.symbol + (this.zero ? "0" : "") + (this.width === undefined ? "" : Math.max(1, this.width | 0)) + (this.comma ? "," : "") + (this.precision === undefined ? "" : "." + Math.max(0, this.precision | 0)) + (this.trim ? "~" : "") + this.type;
42821         };
42822
42823         // Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.
42824         function formatTrim (s) {
42825           out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
42826             switch (s[i]) {
42827               case ".":
42828                 i0 = i1 = i;
42829                 break;
42830
42831               case "0":
42832                 if (i0 === 0) i0 = i;
42833                 i1 = i;
42834                 break;
42835
42836               default:
42837                 if (!+s[i]) break out;
42838                 if (i0 > 0) i0 = 0;
42839                 break;
42840             }
42841           }
42842
42843           return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
42844         }
42845
42846         var nativeToPrecision = 1.0.toPrecision;
42847
42848         var FORCED$1 = fails(function () {
42849           // IE7-
42850           return nativeToPrecision.call(1, undefined) !== '1';
42851         }) || !fails(function () {
42852           // V8 ~ Android 4.3-
42853           nativeToPrecision.call({});
42854         });
42855
42856         // `Number.prototype.toPrecision` method
42857         // https://tc39.es/ecma262/#sec-number.prototype.toprecision
42858         _export({ target: 'Number', proto: true, forced: FORCED$1 }, {
42859           toPrecision: function toPrecision(precision) {
42860             return precision === undefined
42861               ? nativeToPrecision.call(thisNumberValue(this))
42862               : nativeToPrecision.call(thisNumberValue(this), precision);
42863           }
42864         });
42865
42866         var prefixExponent;
42867         function formatPrefixAuto (x, p) {
42868           var d = formatDecimalParts(x, p);
42869           if (!d) return x + "";
42870           var coefficient = d[0],
42871               exponent = d[1],
42872               i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
42873               n = coefficient.length;
42874           return i === n ? coefficient : i > n ? coefficient + new Array(i - n + 1).join("0") : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i) : "0." + new Array(1 - i).join("0") + formatDecimalParts(x, Math.max(0, p + i - 1))[0]; // less than 1y!
42875         }
42876
42877         function formatRounded (x, p) {
42878           var d = formatDecimalParts(x, p);
42879           if (!d) return x + "";
42880           var coefficient = d[0],
42881               exponent = d[1];
42882           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");
42883         }
42884
42885         var formatTypes = {
42886           "%": function _(x, p) {
42887             return (x * 100).toFixed(p);
42888           },
42889           "b": function b(x) {
42890             return Math.round(x).toString(2);
42891           },
42892           "c": function c(x) {
42893             return x + "";
42894           },
42895           "d": formatDecimal,
42896           "e": function e(x, p) {
42897             return x.toExponential(p);
42898           },
42899           "f": function f(x, p) {
42900             return x.toFixed(p);
42901           },
42902           "g": function g(x, p) {
42903             return x.toPrecision(p);
42904           },
42905           "o": function o(x) {
42906             return Math.round(x).toString(8);
42907           },
42908           "p": function p(x, _p) {
42909             return formatRounded(x * 100, _p);
42910           },
42911           "r": formatRounded,
42912           "s": formatPrefixAuto,
42913           "X": function X(x) {
42914             return Math.round(x).toString(16).toUpperCase();
42915           },
42916           "x": function x(_x) {
42917             return Math.round(_x).toString(16);
42918           }
42919         };
42920
42921         function identity (x) {
42922           return x;
42923         }
42924
42925         var map$1 = Array.prototype.map,
42926             prefixes = ["y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
42927         function formatLocale (locale) {
42928           var group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(map$1.call(locale.grouping, Number), locale.thousands + ""),
42929               currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
42930               currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
42931               decimal = locale.decimal === undefined ? "." : locale.decimal + "",
42932               numerals = locale.numerals === undefined ? identity : formatNumerals(map$1.call(locale.numerals, String)),
42933               percent = locale.percent === undefined ? "%" : locale.percent + "",
42934               minus = locale.minus === undefined ? "−" : locale.minus + "",
42935               nan = locale.nan === undefined ? "NaN" : locale.nan + "";
42936
42937           function newFormat(specifier) {
42938             specifier = formatSpecifier(specifier);
42939             var fill = specifier.fill,
42940                 align = specifier.align,
42941                 sign = specifier.sign,
42942                 symbol = specifier.symbol,
42943                 zero = specifier.zero,
42944                 width = specifier.width,
42945                 comma = specifier.comma,
42946                 precision = specifier.precision,
42947                 trim = specifier.trim,
42948                 type = specifier.type; // The "n" type is an alias for ",g".
42949
42950             if (type === "n") comma = true, type = "g"; // The "" type, and any invalid type, is an alias for ".12~g".
42951             else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g"; // If zero fill is specified, padding goes after sign and before digits.
42952
42953             if (zero || fill === "0" && align === "=") zero = true, fill = "0", align = "="; // Compute the prefix and suffix.
42954             // For SI-prefix, the suffix is lazily computed.
42955
42956             var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
42957                 suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : ""; // What format function should we use?
42958             // Is this an integer type?
42959             // Can this type generate exponential notation?
42960
42961             var formatType = formatTypes[type],
42962                 maybeSuffix = /[defgprs%]/.test(type); // Set the default precision if not specified,
42963             // or clamp the specified precision to the supported range.
42964             // For significant precision, it must be in [1, 21].
42965             // For fixed precision, it must be in [0, 20].
42966
42967             precision = precision === undefined ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
42968
42969             function format(value) {
42970               var valuePrefix = prefix,
42971                   valueSuffix = suffix,
42972                   i,
42973                   n,
42974                   c;
42975
42976               if (type === "c") {
42977                 valueSuffix = formatType(value) + valueSuffix;
42978                 value = "";
42979               } else {
42980                 value = +value; // Determine the sign. -0 is not less than 0, but 1 / -0 is!
42981
42982                 var valueNegative = value < 0 || 1 / value < 0; // Perform the initial formatting.
42983
42984                 value = isNaN(value) ? nan : formatType(Math.abs(value), precision); // Trim insignificant zeros.
42985
42986                 if (trim) value = formatTrim(value); // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
42987
42988                 if (valueNegative && +value === 0 && sign !== "+") valueNegative = false; // Compute the prefix and suffix.
42989
42990                 valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
42991                 valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : ""); // Break the formatted value into the integer “value” part that can be
42992                 // grouped, and fractional or exponential “suffix” part that is not.
42993
42994                 if (maybeSuffix) {
42995                   i = -1, n = value.length;
42996
42997                   while (++i < n) {
42998                     if (c = value.charCodeAt(i), 48 > c || c > 57) {
42999                       valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
43000                       value = value.slice(0, i);
43001                       break;
43002                     }
43003                   }
43004                 }
43005               } // If the fill character is not "0", grouping is applied before padding.
43006
43007
43008               if (comma && !zero) value = group(value, Infinity); // Compute the padding.
43009
43010               var length = valuePrefix.length + value.length + valueSuffix.length,
43011                   padding = length < width ? new Array(width - length + 1).join(fill) : ""; // If the fill character is "0", grouping is applied after padding.
43012
43013               if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = ""; // Reconstruct the final output based on the desired alignment.
43014
43015               switch (align) {
43016                 case "<":
43017                   value = valuePrefix + value + valueSuffix + padding;
43018                   break;
43019
43020                 case "=":
43021                   value = valuePrefix + padding + value + valueSuffix;
43022                   break;
43023
43024                 case "^":
43025                   value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
43026                   break;
43027
43028                 default:
43029                   value = padding + valuePrefix + value + valueSuffix;
43030                   break;
43031               }
43032
43033               return numerals(value);
43034             }
43035
43036             format.toString = function () {
43037               return specifier + "";
43038             };
43039
43040             return format;
43041           }
43042
43043           function formatPrefix(specifier, value) {
43044             var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
43045                 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
43046                 k = Math.pow(10, -e),
43047                 prefix = prefixes[8 + e / 3];
43048             return function (value) {
43049               return f(k * value) + prefix;
43050             };
43051           }
43052
43053           return {
43054             format: newFormat,
43055             formatPrefix: formatPrefix
43056           };
43057         }
43058
43059         var locale;
43060         var format;
43061         var formatPrefix;
43062         defaultLocale({
43063           thousands: ",",
43064           grouping: [3],
43065           currency: ["$", ""]
43066         });
43067         function defaultLocale(definition) {
43068           locale = formatLocale(definition);
43069           format = locale.format;
43070           formatPrefix = locale.formatPrefix;
43071           return locale;
43072         }
43073
43074         function precisionFixed (step) {
43075           return Math.max(0, -exponent(Math.abs(step)));
43076         }
43077
43078         function precisionPrefix (step, value) {
43079           return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
43080         }
43081
43082         function precisionRound (step, max) {
43083           step = Math.abs(step), max = Math.abs(max) - step;
43084           return Math.max(0, exponent(max) - exponent(step)) + 1;
43085         }
43086
43087         function tickFormat(start, stop, count, specifier) {
43088           var step = tickStep(start, stop, count),
43089               precision;
43090           specifier = formatSpecifier(specifier == null ? ",f" : specifier);
43091
43092           switch (specifier.type) {
43093             case "s":
43094               {
43095                 var value = Math.max(Math.abs(start), Math.abs(stop));
43096                 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
43097                 return formatPrefix(specifier, value);
43098               }
43099
43100             case "":
43101             case "e":
43102             case "g":
43103             case "p":
43104             case "r":
43105               {
43106                 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
43107                 break;
43108               }
43109
43110             case "f":
43111             case "%":
43112               {
43113                 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
43114                 break;
43115               }
43116           }
43117
43118           return format(specifier);
43119         }
43120
43121         function linearish(scale) {
43122           var domain = scale.domain;
43123
43124           scale.ticks = function (count) {
43125             var d = domain();
43126             return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
43127           };
43128
43129           scale.tickFormat = function (count, specifier) {
43130             var d = domain();
43131             return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
43132           };
43133
43134           scale.nice = function (count) {
43135             if (count == null) count = 10;
43136             var d = domain();
43137             var i0 = 0;
43138             var i1 = d.length - 1;
43139             var start = d[i0];
43140             var stop = d[i1];
43141             var prestep;
43142             var step;
43143             var maxIter = 10;
43144
43145             if (stop < start) {
43146               step = start, start = stop, stop = step;
43147               step = i0, i0 = i1, i1 = step;
43148             }
43149
43150             while (maxIter-- > 0) {
43151               step = tickIncrement(start, stop, count);
43152
43153               if (step === prestep) {
43154                 d[i0] = start;
43155                 d[i1] = stop;
43156                 return domain(d);
43157               } else if (step > 0) {
43158                 start = Math.floor(start / step) * step;
43159                 stop = Math.ceil(stop / step) * step;
43160               } else if (step < 0) {
43161                 start = Math.ceil(start * step) / step;
43162                 stop = Math.floor(stop * step) / step;
43163               } else {
43164                 break;
43165               }
43166
43167               prestep = step;
43168             }
43169
43170             return scale;
43171           };
43172
43173           return scale;
43174         }
43175         function linear() {
43176           var scale = continuous();
43177
43178           scale.copy = function () {
43179             return copy$1(scale, linear());
43180           };
43181
43182           initRange.apply(scale, arguments);
43183           return linearish(scale);
43184         }
43185
43186         // eslint-disable-next-line es/no-math-expm1 -- safe
43187         var $expm1 = Math.expm1;
43188         var exp$1 = Math.exp;
43189
43190         // `Math.expm1` method implementation
43191         // https://tc39.es/ecma262/#sec-math.expm1
43192         var mathExpm1 = (!$expm1
43193           // Old FF bug
43194           || $expm1(10) > 22025.465794806719 || $expm1(10) < 22025.4657948067165168
43195           // Tor Browser bug
43196           || $expm1(-2e-17) != -2e-17
43197         ) ? function expm1(x) {
43198           return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : exp$1(x) - 1;
43199         } : $expm1;
43200
43201         function quantize() {
43202           var x0 = 0,
43203               x1 = 1,
43204               n = 1,
43205               domain = [0.5],
43206               range = [0, 1],
43207               unknown;
43208
43209           function scale(x) {
43210             return x != null && x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
43211           }
43212
43213           function rescale() {
43214             var i = -1;
43215             domain = new Array(n);
43216
43217             while (++i < n) {
43218               domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
43219             }
43220
43221             return scale;
43222           }
43223
43224           scale.domain = function (_) {
43225             var _ref, _ref2;
43226
43227             return arguments.length ? ((_ref = _, _ref2 = _slicedToArray(_ref, 2), x0 = _ref2[0], x1 = _ref2[1], _ref), x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
43228           };
43229
43230           scale.range = function (_) {
43231             return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
43232           };
43233
43234           scale.invertExtent = function (y) {
43235             var i = range.indexOf(y);
43236             return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
43237           };
43238
43239           scale.unknown = function (_) {
43240             return arguments.length ? (unknown = _, scale) : scale;
43241           };
43242
43243           scale.thresholds = function () {
43244             return domain.slice();
43245           };
43246
43247           scale.copy = function () {
43248             return quantize().domain([x0, x1]).range(range).unknown(unknown);
43249           };
43250
43251           return initRange.apply(linearish(scale), arguments);
43252         }
43253
43254         // https://github.com/tc39/proposal-string-pad-start-end
43255
43256
43257
43258
43259         var ceil = Math.ceil;
43260
43261         // `String.prototype.{ padStart, padEnd }` methods implementation
43262         var createMethod = function (IS_END) {
43263           return function ($this, maxLength, fillString) {
43264             var S = String(requireObjectCoercible($this));
43265             var stringLength = S.length;
43266             var fillStr = fillString === undefined ? ' ' : String(fillString);
43267             var intMaxLength = toLength(maxLength);
43268             var fillLen, stringFiller;
43269             if (intMaxLength <= stringLength || fillStr == '') return S;
43270             fillLen = intMaxLength - stringLength;
43271             stringFiller = stringRepeat.call(fillStr, ceil(fillLen / fillStr.length));
43272             if (stringFiller.length > fillLen) stringFiller = stringFiller.slice(0, fillLen);
43273             return IS_END ? S + stringFiller : stringFiller + S;
43274           };
43275         };
43276
43277         var stringPad = {
43278           // `String.prototype.padStart` method
43279           // https://tc39.es/ecma262/#sec-string.prototype.padstart
43280           start: createMethod(false),
43281           // `String.prototype.padEnd` method
43282           // https://tc39.es/ecma262/#sec-string.prototype.padend
43283           end: createMethod(true)
43284         };
43285
43286         var padStart = stringPad.start;
43287
43288         var abs$1 = Math.abs;
43289         var DatePrototype = Date.prototype;
43290         var getTime = DatePrototype.getTime;
43291         var nativeDateToISOString = DatePrototype.toISOString;
43292
43293         // `Date.prototype.toISOString` method implementation
43294         // https://tc39.es/ecma262/#sec-date.prototype.toisostring
43295         // PhantomJS / old WebKit fails here:
43296         var dateToIsoString = (fails(function () {
43297           return nativeDateToISOString.call(new Date(-5e13 - 1)) != '0385-07-25T07:06:39.999Z';
43298         }) || !fails(function () {
43299           nativeDateToISOString.call(new Date(NaN));
43300         })) ? function toISOString() {
43301           if (!isFinite(getTime.call(this))) throw RangeError('Invalid time value');
43302           var date = this;
43303           var year = date.getUTCFullYear();
43304           var milliseconds = date.getUTCMilliseconds();
43305           var sign = year < 0 ? '-' : year > 9999 ? '+' : '';
43306           return sign + padStart(abs$1(year), sign ? 6 : 4, 0) +
43307             '-' + padStart(date.getUTCMonth() + 1, 2, 0) +
43308             '-' + padStart(date.getUTCDate(), 2, 0) +
43309             'T' + padStart(date.getUTCHours(), 2, 0) +
43310             ':' + padStart(date.getUTCMinutes(), 2, 0) +
43311             ':' + padStart(date.getUTCSeconds(), 2, 0) +
43312             '.' + padStart(milliseconds, 3, 0) +
43313             'Z';
43314         } : nativeDateToISOString;
43315
43316         // `Date.prototype.toISOString` method
43317         // https://tc39.es/ecma262/#sec-date.prototype.toisostring
43318         // PhantomJS / old WebKit has a broken implementations
43319         _export({ target: 'Date', proto: true, forced: Date.prototype.toISOString !== dateToIsoString }, {
43320           toISOString: dateToIsoString
43321         });
43322
43323         function behaviorBreathe() {
43324           var duration = 800;
43325           var steps = 4;
43326           var selector = '.selected.shadow, .selected .shadow';
43327
43328           var _selected = select(null);
43329
43330           var _classed = '';
43331           var _params = {};
43332           var _done = false;
43333
43334           var _timer;
43335
43336           function ratchetyInterpolator(a, b, steps, units) {
43337             a = parseFloat(a);
43338             b = parseFloat(b);
43339             var sample = quantize().domain([0, 1]).range(d3_quantize(d3_interpolateNumber(a, b), steps));
43340             return function (t) {
43341               return String(sample(t)) + (units || '');
43342             };
43343           }
43344
43345           function reset(selection) {
43346             selection.style('stroke-opacity', null).style('stroke-width', null).style('fill-opacity', null).style('r', null);
43347           }
43348
43349           function setAnimationParams(transition, fromTo) {
43350             var toFrom = fromTo === 'from' ? 'to' : 'from';
43351             transition.styleTween('stroke-opacity', function (d) {
43352               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
43353             }).styleTween('stroke-width', function (d) {
43354               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
43355             }).styleTween('fill-opacity', function (d) {
43356               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
43357             }).styleTween('r', function (d) {
43358               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
43359             });
43360           }
43361
43362           function calcAnimationParams(selection) {
43363             selection.call(reset).each(function (d) {
43364               var s = select(this);
43365               var tag = s.node().tagName;
43366               var p = {
43367                 'from': {},
43368                 'to': {}
43369               };
43370               var opacity;
43371               var width; // determine base opacity and width
43372
43373               if (tag === 'circle') {
43374                 opacity = parseFloat(s.style('fill-opacity') || 0.5);
43375                 width = parseFloat(s.style('r') || 15.5);
43376               } else {
43377                 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
43378                 width = parseFloat(s.style('stroke-width') || 10);
43379               } // calculate from/to interpolation params..
43380
43381
43382               p.tag = tag;
43383               p.from.opacity = opacity * 0.6;
43384               p.to.opacity = opacity * 1.25;
43385               p.from.width = width * 0.7;
43386               p.to.width = width * (tag === 'circle' ? 1.5 : 1);
43387               _params[d.id] = p;
43388             });
43389           }
43390
43391           function run(surface, fromTo) {
43392             var toFrom = fromTo === 'from' ? 'to' : 'from';
43393             var currSelected = surface.selectAll(selector);
43394             var currClassed = surface.attr('class');
43395
43396             if (_done || currSelected.empty()) {
43397               _selected.call(reset);
43398
43399               _selected = select(null);
43400               return;
43401             }
43402
43403             if (!fastDeepEqual(currSelected.data(), _selected.data()) || currClassed !== _classed) {
43404               _selected.call(reset);
43405
43406               _classed = currClassed;
43407               _selected = currSelected.call(calcAnimationParams);
43408             }
43409
43410             var didCallNextRun = false;
43411
43412             _selected.transition().duration(duration).call(setAnimationParams, fromTo).on('end', function () {
43413               // `end` event is called for each selected element, but we want
43414               // it to run only once
43415               if (!didCallNextRun) {
43416                 surface.call(run, toFrom);
43417                 didCallNextRun = true;
43418               } // if entity was deselected, remove breathe styling
43419
43420
43421               if (!select(this).classed('selected')) {
43422                 reset(select(this));
43423               }
43424             });
43425           }
43426
43427           function behavior(surface) {
43428             _done = false;
43429             _timer = timer(function () {
43430               // wait for elements to actually become selected
43431               if (surface.selectAll(selector).empty()) {
43432                 return false;
43433               }
43434
43435               surface.call(run, 'from');
43436
43437               _timer.stop();
43438
43439               return true;
43440             }, 20);
43441           }
43442
43443           behavior.restartIfNeeded = function (surface) {
43444             if (_selected.empty()) {
43445               surface.call(run, 'from');
43446
43447               if (_timer) {
43448                 _timer.stop();
43449               }
43450             }
43451           };
43452
43453           behavior.off = function () {
43454             _done = true;
43455
43456             if (_timer) {
43457               _timer.stop();
43458             }
43459
43460             _selected.interrupt().call(reset);
43461           };
43462
43463           return behavior;
43464         }
43465
43466         /* Creates a keybinding behavior for an operation */
43467         function behaviorOperation(context) {
43468           var _operation;
43469
43470           function keypress(d3_event) {
43471             // prevent operations during low zoom selection
43472             if (!context.map().withinEditableZoom()) return;
43473             if (_operation.availableForKeypress && !_operation.availableForKeypress()) return;
43474             d3_event.preventDefault();
43475
43476             var disabled = _operation.disabled();
43477
43478             if (disabled) {
43479               context.ui().flash.duration(4000).iconName('#iD-operation-' + _operation.id).iconClass('operation disabled').label(_operation.tooltip)();
43480             } else {
43481               context.ui().flash.duration(2000).iconName('#iD-operation-' + _operation.id).iconClass('operation').label(_operation.annotation() || _operation.title)();
43482               if (_operation.point) _operation.point(null);
43483
43484               _operation();
43485             }
43486           }
43487
43488           function behavior() {
43489             if (_operation && _operation.available()) {
43490               context.keybinding().on(_operation.keys, keypress);
43491             }
43492
43493             return behavior;
43494           }
43495
43496           behavior.off = function () {
43497             context.keybinding().off(_operation.keys);
43498           };
43499
43500           behavior.which = function (_) {
43501             if (!arguments.length) return _operation;
43502             _operation = _;
43503             return behavior;
43504           };
43505
43506           return behavior;
43507         }
43508
43509         function operationCircularize(context, selectedIDs) {
43510           var _extent;
43511
43512           var _actions = selectedIDs.map(getAction).filter(Boolean);
43513
43514           var _amount = _actions.length === 1 ? 'single' : 'multiple';
43515
43516           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
43517             return n.loc;
43518           });
43519
43520           function getAction(entityID) {
43521             var entity = context.entity(entityID);
43522             if (entity.type !== 'way' || new Set(entity.nodes).size <= 1) return null;
43523
43524             if (!_extent) {
43525               _extent = entity.extent(context.graph());
43526             } else {
43527               _extent = _extent.extend(entity.extent(context.graph()));
43528             }
43529
43530             return actionCircularize(entityID, context.projection);
43531           }
43532
43533           var operation = function operation() {
43534             if (!_actions.length) return;
43535
43536             var combinedAction = function combinedAction(graph, t) {
43537               _actions.forEach(function (action) {
43538                 if (!action.disabled(graph)) {
43539                   graph = action(graph, t);
43540                 }
43541               });
43542
43543               return graph;
43544             };
43545
43546             combinedAction.transitionable = true;
43547             context.perform(combinedAction, operation.annotation());
43548             window.setTimeout(function () {
43549               context.validator().validate();
43550             }, 300); // after any transition
43551           };
43552
43553           operation.available = function () {
43554             return _actions.length && selectedIDs.length === _actions.length;
43555           }; // don't cache this because the visible extent could change
43556
43557
43558           operation.disabled = function () {
43559             if (!_actions.length) return '';
43560
43561             var actionDisableds = _actions.map(function (action) {
43562               return action.disabled(context.graph());
43563             }).filter(Boolean);
43564
43565             if (actionDisableds.length === _actions.length) {
43566               // none of the features can be circularized
43567               if (new Set(actionDisableds).size > 1) {
43568                 return 'multiple_blockers';
43569               }
43570
43571               return actionDisableds[0];
43572             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
43573               return 'too_large';
43574             } else if (someMissing()) {
43575               return 'not_downloaded';
43576             } else if (selectedIDs.some(context.hasHiddenConnections)) {
43577               return 'connected_to_hidden';
43578             }
43579
43580             return false;
43581
43582             function someMissing() {
43583               if (context.inIntro()) return false;
43584               var osm = context.connection();
43585
43586               if (osm) {
43587                 var missing = _coords.filter(function (loc) {
43588                   return !osm.isDataLoaded(loc);
43589                 });
43590
43591                 if (missing.length) {
43592                   missing.forEach(function (loc) {
43593                     context.loadTileAtLoc(loc);
43594                   });
43595                   return true;
43596                 }
43597               }
43598
43599               return false;
43600             }
43601           };
43602
43603           operation.tooltip = function () {
43604             var disable = operation.disabled();
43605             return disable ? _t('operations.circularize.' + disable + '.' + _amount) : _t('operations.circularize.description.' + _amount);
43606           };
43607
43608           operation.annotation = function () {
43609             return _t('operations.circularize.annotation.feature', {
43610               n: _actions.length
43611             });
43612           };
43613
43614           operation.id = 'circularize';
43615           operation.keys = [_t('operations.circularize.key')];
43616           operation.title = _t('operations.circularize.title');
43617           operation.behavior = behaviorOperation(context).which(operation);
43618           return operation;
43619         }
43620
43621         // For example, ⌘Z -> Ctrl+Z
43622
43623         var uiCmd = function uiCmd(code) {
43624           var detected = utilDetect();
43625
43626           if (detected.os === 'mac') {
43627             return code;
43628           }
43629
43630           if (detected.os === 'win') {
43631             if (code === '⌘⇧Z') return 'Ctrl+Y';
43632           }
43633
43634           var result = '',
43635               replacements = {
43636             '⌘': 'Ctrl',
43637             '⇧': 'Shift',
43638             '⌥': 'Alt',
43639             '⌫': 'Backspace',
43640             '⌦': 'Delete'
43641           };
43642
43643           for (var i = 0; i < code.length; i++) {
43644             if (code[i] in replacements) {
43645               result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
43646             } else {
43647               result += code[i];
43648             }
43649           }
43650
43651           return result;
43652         }; // return a display-focused string for a given keyboard code
43653
43654         uiCmd.display = function (code) {
43655           if (code.length !== 1) return code;
43656           var detected = utilDetect();
43657           var mac = detected.os === 'mac';
43658           var replacements = {
43659             '⌘': mac ? '⌘ ' + _t('shortcuts.key.cmd') : _t('shortcuts.key.ctrl'),
43660             '⇧': mac ? '⇧ ' + _t('shortcuts.key.shift') : _t('shortcuts.key.shift'),
43661             '⌥': mac ? '⌥ ' + _t('shortcuts.key.option') : _t('shortcuts.key.alt'),
43662             '⌃': mac ? '⌃ ' + _t('shortcuts.key.ctrl') : _t('shortcuts.key.ctrl'),
43663             '⌫': mac ? '⌫ ' + _t('shortcuts.key.delete') : _t('shortcuts.key.backspace'),
43664             '⌦': mac ? '⌦ ' + _t('shortcuts.key.del') : _t('shortcuts.key.del'),
43665             '↖': mac ? '↖ ' + _t('shortcuts.key.pgup') : _t('shortcuts.key.pgup'),
43666             '↘': mac ? '↘ ' + _t('shortcuts.key.pgdn') : _t('shortcuts.key.pgdn'),
43667             '⇞': mac ? '⇞ ' + _t('shortcuts.key.home') : _t('shortcuts.key.home'),
43668             '⇟': mac ? '⇟ ' + _t('shortcuts.key.end') : _t('shortcuts.key.end'),
43669             '↵': mac ? '⏎ ' + _t('shortcuts.key.return') : _t('shortcuts.key.enter'),
43670             '⎋': mac ? '⎋ ' + _t('shortcuts.key.esc') : _t('shortcuts.key.esc'),
43671             '☰': mac ? '☰ ' + _t('shortcuts.key.menu') : _t('shortcuts.key.menu')
43672           };
43673           return replacements[code] || code;
43674         };
43675
43676         function operationDelete(context, selectedIDs) {
43677           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
43678           var action = actionDeleteMultiple(selectedIDs);
43679           var nodes = utilGetAllNodes(selectedIDs, context.graph());
43680           var coords = nodes.map(function (n) {
43681             return n.loc;
43682           });
43683           var extent = utilTotalExtent(selectedIDs, context.graph());
43684
43685           var operation = function operation() {
43686             var nextSelectedID;
43687             var nextSelectedLoc;
43688
43689             if (selectedIDs.length === 1) {
43690               var id = selectedIDs[0];
43691               var entity = context.entity(id);
43692               var geometry = entity.geometry(context.graph());
43693               var parents = context.graph().parentWays(entity);
43694               var parent = parents[0]; // Select the next closest node in the way.
43695
43696               if (geometry === 'vertex') {
43697                 var nodes = parent.nodes;
43698                 var i = nodes.indexOf(id);
43699
43700                 if (i === 0) {
43701                   i++;
43702                 } else if (i === nodes.length - 1) {
43703                   i--;
43704                 } else {
43705                   var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc);
43706                   var b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
43707                   i = a < b ? i - 1 : i + 1;
43708                 }
43709
43710                 nextSelectedID = nodes[i];
43711                 nextSelectedLoc = context.entity(nextSelectedID).loc;
43712               }
43713             }
43714
43715             context.perform(action, operation.annotation());
43716             context.validator().validate();
43717
43718             if (nextSelectedID && nextSelectedLoc) {
43719               if (context.hasEntity(nextSelectedID)) {
43720                 context.enter(modeSelect(context, [nextSelectedID]).follow(true));
43721               } else {
43722                 context.map().centerEase(nextSelectedLoc);
43723                 context.enter(modeBrowse(context));
43724               }
43725             } else {
43726               context.enter(modeBrowse(context));
43727             }
43728           };
43729
43730           operation.available = function () {
43731             return true;
43732           };
43733
43734           operation.disabled = function () {
43735             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
43736               return 'too_large';
43737             } else if (someMissing()) {
43738               return 'not_downloaded';
43739             } else if (selectedIDs.some(context.hasHiddenConnections)) {
43740               return 'connected_to_hidden';
43741             } else if (selectedIDs.some(protectedMember)) {
43742               return 'part_of_relation';
43743             } else if (selectedIDs.some(incompleteRelation)) {
43744               return 'incomplete_relation';
43745             } else if (selectedIDs.some(hasWikidataTag)) {
43746               return 'has_wikidata_tag';
43747             }
43748
43749             return false;
43750
43751             function someMissing() {
43752               if (context.inIntro()) return false;
43753               var osm = context.connection();
43754
43755               if (osm) {
43756                 var missing = coords.filter(function (loc) {
43757                   return !osm.isDataLoaded(loc);
43758                 });
43759
43760                 if (missing.length) {
43761                   missing.forEach(function (loc) {
43762                     context.loadTileAtLoc(loc);
43763                   });
43764                   return true;
43765                 }
43766               }
43767
43768               return false;
43769             }
43770
43771             function hasWikidataTag(id) {
43772               var entity = context.entity(id);
43773               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
43774             }
43775
43776             function incompleteRelation(id) {
43777               var entity = context.entity(id);
43778               return entity.type === 'relation' && !entity.isComplete(context.graph());
43779             }
43780
43781             function protectedMember(id) {
43782               var entity = context.entity(id);
43783               if (entity.type !== 'way') return false;
43784               var parents = context.graph().parentRelations(entity);
43785
43786               for (var i = 0; i < parents.length; i++) {
43787                 var parent = parents[i];
43788                 var type = parent.tags.type;
43789                 var role = parent.memberById(id).role || 'outer';
43790
43791                 if (type === 'route' || type === 'boundary' || type === 'multipolygon' && role === 'outer') {
43792                   return true;
43793                 }
43794               }
43795
43796               return false;
43797             }
43798           };
43799
43800           operation.tooltip = function () {
43801             var disable = operation.disabled();
43802             return disable ? _t('operations.delete.' + disable + '.' + multi) : _t('operations.delete.description.' + multi);
43803           };
43804
43805           operation.annotation = function () {
43806             return selectedIDs.length === 1 ? _t('operations.delete.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.delete.annotation.feature', {
43807               n: selectedIDs.length
43808             });
43809           };
43810
43811           operation.id = 'delete';
43812           operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
43813           operation.title = _t('operations.delete.title');
43814           operation.behavior = behaviorOperation(context).which(operation);
43815           return operation;
43816         }
43817
43818         function operationOrthogonalize(context, selectedIDs) {
43819           var _extent;
43820
43821           var _type;
43822
43823           var _actions = selectedIDs.map(chooseAction).filter(Boolean);
43824
43825           var _amount = _actions.length === 1 ? 'single' : 'multiple';
43826
43827           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
43828             return n.loc;
43829           });
43830
43831           function chooseAction(entityID) {
43832             var entity = context.entity(entityID);
43833             var geometry = entity.geometry(context.graph());
43834
43835             if (!_extent) {
43836               _extent = entity.extent(context.graph());
43837             } else {
43838               _extent = _extent.extend(entity.extent(context.graph()));
43839             } // square a line/area
43840
43841
43842             if (entity.type === 'way' && new Set(entity.nodes).size > 2) {
43843               if (_type && _type !== 'feature') return null;
43844               _type = 'feature';
43845               return actionOrthogonalize(entityID, context.projection); // square a single vertex
43846             } else if (geometry === 'vertex') {
43847               if (_type && _type !== 'corner') return null;
43848               _type = 'corner';
43849               var graph = context.graph();
43850               var parents = graph.parentWays(entity);
43851
43852               if (parents.length === 1) {
43853                 var way = parents[0];
43854
43855                 if (way.nodes.indexOf(entityID) !== -1) {
43856                   return actionOrthogonalize(way.id, context.projection, entityID);
43857                 }
43858               }
43859             }
43860
43861             return null;
43862           }
43863
43864           var operation = function operation() {
43865             if (!_actions.length) return;
43866
43867             var combinedAction = function combinedAction(graph, t) {
43868               _actions.forEach(function (action) {
43869                 if (!action.disabled(graph)) {
43870                   graph = action(graph, t);
43871                 }
43872               });
43873
43874               return graph;
43875             };
43876
43877             combinedAction.transitionable = true;
43878             context.perform(combinedAction, operation.annotation());
43879             window.setTimeout(function () {
43880               context.validator().validate();
43881             }, 300); // after any transition
43882           };
43883
43884           operation.available = function () {
43885             return _actions.length && selectedIDs.length === _actions.length;
43886           }; // don't cache this because the visible extent could change
43887
43888
43889           operation.disabled = function () {
43890             if (!_actions.length) return '';
43891
43892             var actionDisableds = _actions.map(function (action) {
43893               return action.disabled(context.graph());
43894             }).filter(Boolean);
43895
43896             if (actionDisableds.length === _actions.length) {
43897               // none of the features can be squared
43898               if (new Set(actionDisableds).size > 1) {
43899                 return 'multiple_blockers';
43900               }
43901
43902               return actionDisableds[0];
43903             } else if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
43904               return 'too_large';
43905             } else if (someMissing()) {
43906               return 'not_downloaded';
43907             } else if (selectedIDs.some(context.hasHiddenConnections)) {
43908               return 'connected_to_hidden';
43909             }
43910
43911             return false;
43912
43913             function someMissing() {
43914               if (context.inIntro()) return false;
43915               var osm = context.connection();
43916
43917               if (osm) {
43918                 var missing = _coords.filter(function (loc) {
43919                   return !osm.isDataLoaded(loc);
43920                 });
43921
43922                 if (missing.length) {
43923                   missing.forEach(function (loc) {
43924                     context.loadTileAtLoc(loc);
43925                   });
43926                   return true;
43927                 }
43928               }
43929
43930               return false;
43931             }
43932           };
43933
43934           operation.tooltip = function () {
43935             var disable = operation.disabled();
43936             return disable ? _t('operations.orthogonalize.' + disable + '.' + _amount) : _t('operations.orthogonalize.description.' + _type + '.' + _amount);
43937           };
43938
43939           operation.annotation = function () {
43940             return _t('operations.orthogonalize.annotation.' + _type, {
43941               n: _actions.length
43942             });
43943           };
43944
43945           operation.id = 'orthogonalize';
43946           operation.keys = [_t('operations.orthogonalize.key')];
43947           operation.title = _t('operations.orthogonalize.title');
43948           operation.behavior = behaviorOperation(context).which(operation);
43949           return operation;
43950         }
43951
43952         function operationReflectShort(context, selectedIDs) {
43953           return operationReflect(context, selectedIDs, 'short');
43954         }
43955         function operationReflectLong(context, selectedIDs) {
43956           return operationReflect(context, selectedIDs, 'long');
43957         }
43958         function operationReflect(context, selectedIDs, axis) {
43959           axis = axis || 'long';
43960           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
43961           var nodes = utilGetAllNodes(selectedIDs, context.graph());
43962           var coords = nodes.map(function (n) {
43963             return n.loc;
43964           });
43965           var extent = utilTotalExtent(selectedIDs, context.graph());
43966
43967           var operation = function operation() {
43968             var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === 'long'));
43969             context.perform(action, operation.annotation());
43970             window.setTimeout(function () {
43971               context.validator().validate();
43972             }, 300); // after any transition
43973           };
43974
43975           operation.available = function () {
43976             return nodes.length >= 3;
43977           }; // don't cache this because the visible extent could change
43978
43979
43980           operation.disabled = function () {
43981             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
43982               return 'too_large';
43983             } else if (someMissing()) {
43984               return 'not_downloaded';
43985             } else if (selectedIDs.some(context.hasHiddenConnections)) {
43986               return 'connected_to_hidden';
43987             } else if (selectedIDs.some(incompleteRelation)) {
43988               return 'incomplete_relation';
43989             }
43990
43991             return false;
43992
43993             function someMissing() {
43994               if (context.inIntro()) return false;
43995               var osm = context.connection();
43996
43997               if (osm) {
43998                 var missing = coords.filter(function (loc) {
43999                   return !osm.isDataLoaded(loc);
44000                 });
44001
44002                 if (missing.length) {
44003                   missing.forEach(function (loc) {
44004                     context.loadTileAtLoc(loc);
44005                   });
44006                   return true;
44007                 }
44008               }
44009
44010               return false;
44011             }
44012
44013             function incompleteRelation(id) {
44014               var entity = context.entity(id);
44015               return entity.type === 'relation' && !entity.isComplete(context.graph());
44016             }
44017           };
44018
44019           operation.tooltip = function () {
44020             var disable = operation.disabled();
44021             return disable ? _t('operations.reflect.' + disable + '.' + multi) : _t('operations.reflect.description.' + axis + '.' + multi);
44022           };
44023
44024           operation.annotation = function () {
44025             return _t('operations.reflect.annotation.' + axis + '.feature', {
44026               n: selectedIDs.length
44027             });
44028           };
44029
44030           operation.id = 'reflect-' + axis;
44031           operation.keys = [_t('operations.reflect.key.' + axis)];
44032           operation.title = _t('operations.reflect.title.' + axis);
44033           operation.behavior = behaviorOperation(context).which(operation);
44034           return operation;
44035         }
44036
44037         function operationMove(context, selectedIDs) {
44038           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
44039           var nodes = utilGetAllNodes(selectedIDs, context.graph());
44040           var coords = nodes.map(function (n) {
44041             return n.loc;
44042           });
44043           var extent = utilTotalExtent(selectedIDs, context.graph());
44044
44045           var operation = function operation() {
44046             context.enter(modeMove(context, selectedIDs));
44047           };
44048
44049           operation.available = function () {
44050             return selectedIDs.length > 0;
44051           };
44052
44053           operation.disabled = function () {
44054             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
44055               return 'too_large';
44056             } else if (someMissing()) {
44057               return 'not_downloaded';
44058             } else if (selectedIDs.some(context.hasHiddenConnections)) {
44059               return 'connected_to_hidden';
44060             } else if (selectedIDs.some(incompleteRelation)) {
44061               return 'incomplete_relation';
44062             }
44063
44064             return false;
44065
44066             function someMissing() {
44067               if (context.inIntro()) return false;
44068               var osm = context.connection();
44069
44070               if (osm) {
44071                 var missing = coords.filter(function (loc) {
44072                   return !osm.isDataLoaded(loc);
44073                 });
44074
44075                 if (missing.length) {
44076                   missing.forEach(function (loc) {
44077                     context.loadTileAtLoc(loc);
44078                   });
44079                   return true;
44080                 }
44081               }
44082
44083               return false;
44084             }
44085
44086             function incompleteRelation(id) {
44087               var entity = context.entity(id);
44088               return entity.type === 'relation' && !entity.isComplete(context.graph());
44089             }
44090           };
44091
44092           operation.tooltip = function () {
44093             var disable = operation.disabled();
44094             return disable ? _t('operations.move.' + disable + '.' + multi) : _t('operations.move.description.' + multi);
44095           };
44096
44097           operation.annotation = function () {
44098             return selectedIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.move.annotation.feature', {
44099               n: selectedIDs.length
44100             });
44101           };
44102
44103           operation.id = 'move';
44104           operation.keys = [_t('operations.move.key')];
44105           operation.title = _t('operations.move.title');
44106           operation.behavior = behaviorOperation(context).which(operation);
44107           operation.mouseOnly = true;
44108           return operation;
44109         }
44110
44111         function modeRotate(context, entityIDs) {
44112           var _tolerancePx = 4; // see also behaviorDrag, behaviorSelect, modeMove
44113
44114           var mode = {
44115             id: 'rotate',
44116             button: 'browse'
44117           };
44118           var keybinding = utilKeybinding('rotate');
44119           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];
44120           var annotation = entityIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.rotate.annotation.feature', {
44121             n: entityIDs.length
44122           });
44123
44124           var _prevGraph;
44125
44126           var _prevAngle;
44127
44128           var _prevTransform;
44129
44130           var _pivot; // use pointer events on supported platforms; fallback to mouse events
44131
44132
44133           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
44134
44135           function doRotate(d3_event) {
44136             var fn;
44137
44138             if (context.graph() !== _prevGraph) {
44139               fn = context.perform;
44140             } else {
44141               fn = context.replace;
44142             } // projection changed, recalculate _pivot
44143
44144
44145             var projection = context.projection;
44146             var currTransform = projection.transform();
44147
44148             if (!_prevTransform || currTransform.k !== _prevTransform.k || currTransform.x !== _prevTransform.x || currTransform.y !== _prevTransform.y) {
44149               var nodes = utilGetAllNodes(entityIDs, context.graph());
44150               var points = nodes.map(function (n) {
44151                 return projection(n.loc);
44152               });
44153               _pivot = getPivot(points);
44154               _prevAngle = undefined;
44155             }
44156
44157             var currMouse = context.map().mouse(d3_event);
44158             var currAngle = Math.atan2(currMouse[1] - _pivot[1], currMouse[0] - _pivot[0]);
44159             if (typeof _prevAngle === 'undefined') _prevAngle = currAngle;
44160             var delta = currAngle - _prevAngle;
44161             fn(actionRotate(entityIDs, _pivot, delta, projection));
44162             _prevTransform = currTransform;
44163             _prevAngle = currAngle;
44164             _prevGraph = context.graph();
44165           }
44166
44167           function getPivot(points) {
44168             var _pivot;
44169
44170             if (points.length === 1) {
44171               _pivot = points[0];
44172             } else if (points.length === 2) {
44173               _pivot = geoVecInterp(points[0], points[1], 0.5);
44174             } else {
44175               var polygonHull = d3_polygonHull(points);
44176
44177               if (polygonHull.length === 2) {
44178                 _pivot = geoVecInterp(points[0], points[1], 0.5);
44179               } else {
44180                 _pivot = d3_polygonCentroid(d3_polygonHull(points));
44181               }
44182             }
44183
44184             return _pivot;
44185           }
44186
44187           function finish(d3_event) {
44188             d3_event.stopPropagation();
44189             context.replace(actionNoop(), annotation);
44190             context.enter(modeSelect(context, entityIDs));
44191           }
44192
44193           function cancel() {
44194             if (_prevGraph) context.pop(); // remove the rotate
44195
44196             context.enter(modeSelect(context, entityIDs));
44197           }
44198
44199           function undone() {
44200             context.enter(modeBrowse(context));
44201           }
44202
44203           mode.enter = function () {
44204             _prevGraph = null;
44205             context.features().forceVisible(entityIDs);
44206             behaviors.forEach(context.install);
44207             var downEvent;
44208             context.surface().on(_pointerPrefix + 'down.modeRotate', function (d3_event) {
44209               downEvent = d3_event;
44210             });
44211             select(window).on(_pointerPrefix + 'move.modeRotate', doRotate, true).on(_pointerPrefix + 'up.modeRotate', function (d3_event) {
44212               if (!downEvent) return;
44213               var mapNode = context.container().select('.main-map').node();
44214               var pointGetter = utilFastMouse(mapNode);
44215               var p1 = pointGetter(downEvent);
44216               var p2 = pointGetter(d3_event);
44217               var dist = geoVecLength(p1, p2);
44218               if (dist <= _tolerancePx) finish(d3_event);
44219               downEvent = null;
44220             }, true);
44221             context.history().on('undone.modeRotate', undone);
44222             keybinding.on('⎋', cancel).on('↩', finish);
44223             select(document).call(keybinding);
44224           };
44225
44226           mode.exit = function () {
44227             behaviors.forEach(context.uninstall);
44228             context.surface().on(_pointerPrefix + 'down.modeRotate', null);
44229             select(window).on(_pointerPrefix + 'move.modeRotate', null, true).on(_pointerPrefix + 'up.modeRotate', null, true);
44230             context.history().on('undone.modeRotate', null);
44231             select(document).call(keybinding.unbind);
44232             context.features().forceVisible([]);
44233           };
44234
44235           mode.selectedIDs = function () {
44236             if (!arguments.length) return entityIDs; // no assign
44237
44238             return mode;
44239           };
44240
44241           return mode;
44242         }
44243
44244         function operationRotate(context, selectedIDs) {
44245           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
44246           var nodes = utilGetAllNodes(selectedIDs, context.graph());
44247           var coords = nodes.map(function (n) {
44248             return n.loc;
44249           });
44250           var extent = utilTotalExtent(selectedIDs, context.graph());
44251
44252           var operation = function operation() {
44253             context.enter(modeRotate(context, selectedIDs));
44254           };
44255
44256           operation.available = function () {
44257             return nodes.length >= 2;
44258           };
44259
44260           operation.disabled = function () {
44261             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
44262               return 'too_large';
44263             } else if (someMissing()) {
44264               return 'not_downloaded';
44265             } else if (selectedIDs.some(context.hasHiddenConnections)) {
44266               return 'connected_to_hidden';
44267             } else if (selectedIDs.some(incompleteRelation)) {
44268               return 'incomplete_relation';
44269             }
44270
44271             return false;
44272
44273             function someMissing() {
44274               if (context.inIntro()) return false;
44275               var osm = context.connection();
44276
44277               if (osm) {
44278                 var missing = coords.filter(function (loc) {
44279                   return !osm.isDataLoaded(loc);
44280                 });
44281
44282                 if (missing.length) {
44283                   missing.forEach(function (loc) {
44284                     context.loadTileAtLoc(loc);
44285                   });
44286                   return true;
44287                 }
44288               }
44289
44290               return false;
44291             }
44292
44293             function incompleteRelation(id) {
44294               var entity = context.entity(id);
44295               return entity.type === 'relation' && !entity.isComplete(context.graph());
44296             }
44297           };
44298
44299           operation.tooltip = function () {
44300             var disable = operation.disabled();
44301             return disable ? _t('operations.rotate.' + disable + '.' + multi) : _t('operations.rotate.description.' + multi);
44302           };
44303
44304           operation.annotation = function () {
44305             return selectedIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.rotate.annotation.feature', {
44306               n: selectedIDs.length
44307             });
44308           };
44309
44310           operation.id = 'rotate';
44311           operation.keys = [_t('operations.rotate.key')];
44312           operation.title = _t('operations.rotate.title');
44313           operation.behavior = behaviorOperation(context).which(operation);
44314           operation.mouseOnly = true;
44315           return operation;
44316         }
44317
44318         function modeMove(context, entityIDs, baseGraph) {
44319           var _tolerancePx = 4; // see also behaviorDrag, behaviorSelect, modeRotate
44320
44321           var mode = {
44322             id: 'move',
44323             button: 'browse'
44324           };
44325           var keybinding = utilKeybinding('move');
44326           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];
44327           var annotation = entityIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.move.annotation.feature', {
44328             n: entityIDs.length
44329           });
44330
44331           var _prevGraph;
44332
44333           var _cache;
44334
44335           var _origin;
44336
44337           var _nudgeInterval; // use pointer events on supported platforms; fallback to mouse events
44338
44339
44340           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
44341
44342           function doMove(nudge) {
44343             nudge = nudge || [0, 0];
44344             var fn;
44345
44346             if (_prevGraph !== context.graph()) {
44347               _cache = {};
44348               _origin = context.map().mouseCoordinates();
44349               fn = context.perform;
44350             } else {
44351               fn = context.overwrite;
44352             }
44353
44354             var currMouse = context.map().mouse();
44355             var origMouse = context.projection(_origin);
44356             var delta = geoVecSubtract(geoVecSubtract(currMouse, origMouse), nudge);
44357             fn(actionMove(entityIDs, delta, context.projection, _cache));
44358             _prevGraph = context.graph();
44359           }
44360
44361           function startNudge(nudge) {
44362             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
44363             _nudgeInterval = window.setInterval(function () {
44364               context.map().pan(nudge);
44365               doMove(nudge);
44366             }, 50);
44367           }
44368
44369           function stopNudge() {
44370             if (_nudgeInterval) {
44371               window.clearInterval(_nudgeInterval);
44372               _nudgeInterval = null;
44373             }
44374           }
44375
44376           function move() {
44377             doMove();
44378             var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
44379
44380             if (nudge) {
44381               startNudge(nudge);
44382             } else {
44383               stopNudge();
44384             }
44385           }
44386
44387           function finish(d3_event) {
44388             d3_event.stopPropagation();
44389             context.replace(actionNoop(), annotation);
44390             context.enter(modeSelect(context, entityIDs));
44391             stopNudge();
44392           }
44393
44394           function cancel() {
44395             if (baseGraph) {
44396               while (context.graph() !== baseGraph) {
44397                 context.pop();
44398               } // reset to baseGraph
44399
44400
44401               context.enter(modeBrowse(context));
44402             } else {
44403               if (_prevGraph) context.pop(); // remove the move
44404
44405               context.enter(modeSelect(context, entityIDs));
44406             }
44407
44408             stopNudge();
44409           }
44410
44411           function undone() {
44412             context.enter(modeBrowse(context));
44413           }
44414
44415           mode.enter = function () {
44416             _origin = context.map().mouseCoordinates();
44417             _prevGraph = null;
44418             _cache = {};
44419             context.features().forceVisible(entityIDs);
44420             behaviors.forEach(context.install);
44421             var downEvent;
44422             context.surface().on(_pointerPrefix + 'down.modeMove', function (d3_event) {
44423               downEvent = d3_event;
44424             });
44425             select(window).on(_pointerPrefix + 'move.modeMove', move, true).on(_pointerPrefix + 'up.modeMove', function (d3_event) {
44426               if (!downEvent) return;
44427               var mapNode = context.container().select('.main-map').node();
44428               var pointGetter = utilFastMouse(mapNode);
44429               var p1 = pointGetter(downEvent);
44430               var p2 = pointGetter(d3_event);
44431               var dist = geoVecLength(p1, p2);
44432               if (dist <= _tolerancePx) finish(d3_event);
44433               downEvent = null;
44434             }, true);
44435             context.history().on('undone.modeMove', undone);
44436             keybinding.on('⎋', cancel).on('↩', finish);
44437             select(document).call(keybinding);
44438           };
44439
44440           mode.exit = function () {
44441             stopNudge();
44442             behaviors.forEach(function (behavior) {
44443               context.uninstall(behavior);
44444             });
44445             context.surface().on(_pointerPrefix + 'down.modeMove', null);
44446             select(window).on(_pointerPrefix + 'move.modeMove', null, true).on(_pointerPrefix + 'up.modeMove', null, true);
44447             context.history().on('undone.modeMove', null);
44448             select(document).call(keybinding.unbind);
44449             context.features().forceVisible([]);
44450           };
44451
44452           mode.selectedIDs = function () {
44453             if (!arguments.length) return entityIDs; // no assign
44454
44455             return mode;
44456           };
44457
44458           return mode;
44459         }
44460
44461         function behaviorPaste(context) {
44462           function doPaste(d3_event) {
44463             // prevent paste during low zoom selection
44464             if (!context.map().withinEditableZoom()) return;
44465             d3_event.preventDefault();
44466             var baseGraph = context.graph();
44467             var mouse = context.map().mouse();
44468             var projection = context.projection;
44469             var viewport = geoExtent(projection.clipExtent()).polygon();
44470             if (!geoPointInPolygon(mouse, viewport)) return;
44471             var oldIDs = context.copyIDs();
44472             if (!oldIDs.length) return;
44473             var extent = geoExtent();
44474             var oldGraph = context.copyGraph();
44475             var newIDs = [];
44476             var action = actionCopyEntities(oldIDs, oldGraph);
44477             context.perform(action);
44478             var copies = action.copies();
44479             var originals = new Set();
44480             Object.values(copies).forEach(function (entity) {
44481               originals.add(entity.id);
44482             });
44483
44484             for (var id in copies) {
44485               var oldEntity = oldGraph.entity(id);
44486               var newEntity = copies[id];
44487
44488               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
44489
44490
44491               var parents = context.graph().parentWays(newEntity);
44492               var parentCopied = parents.some(function (parent) {
44493                 return originals.has(parent.id);
44494               });
44495
44496               if (!parentCopied) {
44497                 newIDs.push(newEntity.id);
44498               }
44499             } // Put pasted objects where mouse pointer is..
44500
44501
44502             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
44503             var delta = geoVecSubtract(mouse, copyPoint);
44504             context.perform(actionMove(newIDs, delta, projection));
44505             context.enter(modeMove(context, newIDs, baseGraph));
44506           }
44507
44508           function behavior() {
44509             context.keybinding().on(uiCmd('⌘V'), doPaste);
44510             return behavior;
44511           }
44512
44513           behavior.off = function () {
44514             context.keybinding().off(uiCmd('⌘V'));
44515           };
44516
44517           return behavior;
44518         }
44519
44520         // `String.prototype.repeat` method
44521         // https://tc39.es/ecma262/#sec-string.prototype.repeat
44522         _export({ target: 'String', proto: true }, {
44523           repeat: stringRepeat
44524         });
44525
44526         /*
44527             `behaviorDrag` is like `d3_behavior.drag`, with the following differences:
44528
44529             * The `origin` function is expected to return an [x, y] tuple rather than an
44530               {x, y} object.
44531             * The events are `start`, `move`, and `end`.
44532               (https://github.com/mbostock/d3/issues/563)
44533             * The `start` event is not dispatched until the first cursor movement occurs.
44534               (https://github.com/mbostock/d3/pull/368)
44535             * The `move` event has a `point` and `delta` [x, y] tuple properties rather
44536               than `x`, `y`, `dx`, and `dy` properties.
44537             * The `end` event is not dispatched if no movement occurs.
44538             * An `off` function is available that unbinds the drag's internal event handlers.
44539          */
44540
44541         function behaviorDrag() {
44542           var dispatch = dispatch$8('start', 'move', 'end'); // see also behaviorSelect
44543
44544           var _tolerancePx = 1; // keep this low to facilitate pixel-perfect micromapping
44545
44546           var _penTolerancePx = 4; // styluses can be touchy so require greater movement - #1981
44547
44548           var _origin = null;
44549           var _selector = '';
44550
44551           var _targetNode;
44552
44553           var _targetEntity;
44554
44555           var _surface;
44556
44557           var _pointerId; // use pointer events on supported platforms; fallback to mouse events
44558
44559
44560           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
44561
44562           var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect');
44563
44564           var d3_event_userSelectSuppress = function d3_event_userSelectSuppress() {
44565             var selection$1 = selection();
44566             var select = selection$1.style(d3_event_userSelectProperty);
44567             selection$1.style(d3_event_userSelectProperty, 'none');
44568             return function () {
44569               selection$1.style(d3_event_userSelectProperty, select);
44570             };
44571           };
44572
44573           function pointerdown(d3_event) {
44574             if (_pointerId) return;
44575             _pointerId = d3_event.pointerId || 'mouse';
44576             _targetNode = this; // only force reflow once per drag
44577
44578             var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
44579             var offset;
44580             var startOrigin = pointerLocGetter(d3_event);
44581             var started = false;
44582             var selectEnable = d3_event_userSelectSuppress();
44583             select(window).on(_pointerPrefix + 'move.drag', pointermove).on(_pointerPrefix + 'up.drag pointercancel.drag', pointerup, true);
44584
44585             if (_origin) {
44586               offset = _origin.call(_targetNode, _targetEntity);
44587               offset = [offset[0] - startOrigin[0], offset[1] - startOrigin[1]];
44588             } else {
44589               offset = [0, 0];
44590             }
44591
44592             d3_event.stopPropagation();
44593
44594             function pointermove(d3_event) {
44595               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
44596               var p = pointerLocGetter(d3_event);
44597
44598               if (!started) {
44599                 var dist = geoVecLength(startOrigin, p);
44600                 var tolerance = d3_event.pointerType === 'pen' ? _penTolerancePx : _tolerancePx; // don't start until the drag has actually moved somewhat
44601
44602                 if (dist < tolerance) return;
44603                 started = true;
44604                 dispatch.call('start', this, d3_event, _targetEntity); // Don't send a `move` event in the same cycle as `start` since dragging
44605                 // a midpoint will convert the target to a node.
44606               } else {
44607                 startOrigin = p;
44608                 d3_event.stopPropagation();
44609                 d3_event.preventDefault();
44610                 var dx = p[0] - startOrigin[0];
44611                 var dy = p[1] - startOrigin[1];
44612                 dispatch.call('move', this, d3_event, _targetEntity, [p[0] + offset[0], p[1] + offset[1]], [dx, dy]);
44613               }
44614             }
44615
44616             function pointerup(d3_event) {
44617               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
44618               _pointerId = null;
44619
44620               if (started) {
44621                 dispatch.call('end', this, d3_event, _targetEntity);
44622                 d3_event.preventDefault();
44623               }
44624
44625               select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
44626               selectEnable();
44627             }
44628           }
44629
44630           function behavior(selection) {
44631             var matchesSelector = utilPrefixDOMProperty('matchesSelector');
44632             var delegate = pointerdown;
44633
44634             if (_selector) {
44635               delegate = function delegate(d3_event) {
44636                 var root = this;
44637                 var target = d3_event.target;
44638
44639                 for (; target && target !== root; target = target.parentNode) {
44640                   var datum = target.__data__;
44641                   _targetEntity = datum instanceof osmNote ? datum : datum && datum.properties && datum.properties.entity;
44642
44643                   if (_targetEntity && target[matchesSelector](_selector)) {
44644                     return pointerdown.call(target, d3_event);
44645                   }
44646                 }
44647               };
44648             }
44649
44650             selection.on(_pointerPrefix + 'down.drag' + _selector, delegate);
44651           }
44652
44653           behavior.off = function (selection) {
44654             selection.on(_pointerPrefix + 'down.drag' + _selector, null);
44655           };
44656
44657           behavior.selector = function (_) {
44658             if (!arguments.length) return _selector;
44659             _selector = _;
44660             return behavior;
44661           };
44662
44663           behavior.origin = function (_) {
44664             if (!arguments.length) return _origin;
44665             _origin = _;
44666             return behavior;
44667           };
44668
44669           behavior.cancel = function () {
44670             select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
44671             return behavior;
44672           };
44673
44674           behavior.targetNode = function (_) {
44675             if (!arguments.length) return _targetNode;
44676             _targetNode = _;
44677             return behavior;
44678           };
44679
44680           behavior.targetEntity = function (_) {
44681             if (!arguments.length) return _targetEntity;
44682             _targetEntity = _;
44683             return behavior;
44684           };
44685
44686           behavior.surface = function (_) {
44687             if (!arguments.length) return _surface;
44688             _surface = _;
44689             return behavior;
44690           };
44691
44692           return utilRebind(behavior, dispatch, 'on');
44693         }
44694
44695         function modeDragNode(context) {
44696           var mode = {
44697             id: 'drag-node',
44698             button: 'browse'
44699           };
44700           var hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover);
44701           var edit = behaviorEdit(context);
44702
44703           var _nudgeInterval;
44704
44705           var _restoreSelectedIDs = [];
44706           var _wasMidpoint = false;
44707           var _isCancelled = false;
44708
44709           var _activeEntity;
44710
44711           var _startLoc;
44712
44713           var _lastLoc;
44714
44715           function startNudge(d3_event, entity, nudge) {
44716             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
44717             _nudgeInterval = window.setInterval(function () {
44718               context.map().pan(nudge);
44719               doMove(d3_event, entity, nudge);
44720             }, 50);
44721           }
44722
44723           function stopNudge() {
44724             if (_nudgeInterval) {
44725               window.clearInterval(_nudgeInterval);
44726               _nudgeInterval = null;
44727             }
44728           }
44729
44730           function moveAnnotation(entity) {
44731             return _t('operations.move.annotation.' + entity.geometry(context.graph()));
44732           }
44733
44734           function connectAnnotation(nodeEntity, targetEntity) {
44735             var nodeGeometry = nodeEntity.geometry(context.graph());
44736             var targetGeometry = targetEntity.geometry(context.graph());
44737
44738             if (nodeGeometry === 'vertex' && targetGeometry === 'vertex') {
44739               var nodeParentWayIDs = context.graph().parentWays(nodeEntity);
44740               var targetParentWayIDs = context.graph().parentWays(targetEntity);
44741               var sharedParentWays = utilArrayIntersection(nodeParentWayIDs, targetParentWayIDs); // if both vertices are part of the same way
44742
44743               if (sharedParentWays.length !== 0) {
44744                 // if the nodes are next to each other, they are merged
44745                 if (sharedParentWays[0].areAdjacent(nodeEntity.id, targetEntity.id)) {
44746                   return _t('operations.connect.annotation.from_vertex.to_adjacent_vertex');
44747                 }
44748
44749                 return _t('operations.connect.annotation.from_vertex.to_sibling_vertex');
44750               }
44751             }
44752
44753             return _t('operations.connect.annotation.from_' + nodeGeometry + '.to_' + targetGeometry);
44754           }
44755
44756           function shouldSnapToNode(target) {
44757             if (!_activeEntity) return false;
44758             return _activeEntity.geometry(context.graph()) !== 'vertex' || target.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(target, context.graph());
44759           }
44760
44761           function origin(entity) {
44762             return context.projection(entity.loc);
44763           }
44764
44765           function keydown(d3_event) {
44766             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
44767               if (context.surface().classed('nope')) {
44768                 context.surface().classed('nope-suppressed', true);
44769               }
44770
44771               context.surface().classed('nope', false).classed('nope-disabled', true);
44772             }
44773           }
44774
44775           function keyup(d3_event) {
44776             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
44777               if (context.surface().classed('nope-suppressed')) {
44778                 context.surface().classed('nope', true);
44779               }
44780
44781               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
44782             }
44783           }
44784
44785           function start(d3_event, entity) {
44786             _wasMidpoint = entity.type === 'midpoint';
44787             var hasHidden = context.features().hasHiddenConnections(entity, context.graph());
44788             _isCancelled = !context.editable() || d3_event.shiftKey || hasHidden;
44789
44790             if (_isCancelled) {
44791               if (hasHidden) {
44792                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('modes.drag_node.connected_to_hidden'))();
44793               }
44794
44795               return drag.cancel();
44796             }
44797
44798             if (_wasMidpoint) {
44799               var midpoint = entity;
44800               entity = osmNode();
44801               context.perform(actionAddMidpoint(midpoint, entity));
44802               entity = context.entity(entity.id); // get post-action entity
44803
44804               var vertex = context.surface().selectAll('.' + entity.id);
44805               drag.targetNode(vertex.node()).targetEntity(entity);
44806             } else {
44807               context.perform(actionNoop());
44808             }
44809
44810             _activeEntity = entity;
44811             _startLoc = entity.loc;
44812             hover.ignoreVertex(entity.geometry(context.graph()) === 'vertex');
44813             context.surface().selectAll('.' + _activeEntity.id).classed('active', true);
44814             context.enter(mode);
44815           } // related code
44816           // - `behavior/draw.js` `datum()`
44817
44818
44819           function datum(d3_event) {
44820             if (!d3_event || d3_event.altKey) {
44821               return {};
44822             } else {
44823               // When dragging, snap only to touch targets..
44824               // (this excludes area fills and active drawing elements)
44825               var d = d3_event.target.__data__;
44826               return d && d.properties && d.properties.target ? d : {};
44827             }
44828           }
44829
44830           function doMove(d3_event, entity, nudge) {
44831             nudge = nudge || [0, 0];
44832             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
44833             var currMouse = geoVecSubtract(currPoint, nudge);
44834             var loc = context.projection.invert(currMouse);
44835             var target, edge;
44836
44837             if (!_nudgeInterval) {
44838               // If not nudging at the edge of the viewport, try to snap..
44839               // related code
44840               // - `mode/drag_node.js`     `doMove()`
44841               // - `behavior/draw.js`      `click()`
44842               // - `behavior/draw_way.js`  `move()`
44843               var d = datum(d3_event);
44844               target = d && d.properties && d.properties.entity;
44845               var targetLoc = target && target.loc;
44846               var targetNodes = d && d.properties && d.properties.nodes;
44847
44848               if (targetLoc) {
44849                 // snap to node/vertex - a point target with `.loc`
44850                 if (shouldSnapToNode(target)) {
44851                   loc = targetLoc;
44852                 }
44853               } else if (targetNodes) {
44854                 // snap to way - a line target with `.nodes`
44855                 edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
44856
44857                 if (edge) {
44858                   loc = edge.loc;
44859                 }
44860               }
44861             }
44862
44863             context.replace(actionMoveNode(entity.id, loc)); // Below here: validations
44864
44865             var isInvalid = false; // Check if this connection to `target` could cause relations to break..
44866
44867             if (target) {
44868               isInvalid = hasRelationConflict(entity, target, edge, context.graph());
44869             } // Check if this drag causes the geometry to break..
44870
44871
44872             if (!isInvalid) {
44873               isInvalid = hasInvalidGeometry(entity, context.graph());
44874             }
44875
44876             var nope = context.surface().classed('nope');
44877
44878             if (isInvalid === 'relation' || isInvalid === 'restriction') {
44879               if (!nope) {
44880                 // about to nope - show hint
44881                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.connect.' + isInvalid, {
44882                   relation: _mainPresetIndex.item('type/restriction').name()
44883                 }))();
44884               }
44885             } else if (isInvalid) {
44886               var errorID = isInvalid === 'line' ? 'lines' : 'areas';
44887               context.ui().flash.duration(3000).iconName('#iD-icon-no').label(_t('self_intersection.error.' + errorID))();
44888             } else {
44889               if (nope) {
44890                 // about to un-nope, remove hint
44891                 context.ui().flash.duration(1).label('')();
44892               }
44893             }
44894
44895             var nopeDisabled = context.surface().classed('nope-disabled');
44896
44897             if (nopeDisabled) {
44898               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
44899             } else {
44900               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
44901             }
44902
44903             _lastLoc = loc;
44904           } // Uses `actionConnect.disabled()` to know whether this connection is ok..
44905
44906
44907           function hasRelationConflict(entity, target, edge, graph) {
44908             var testGraph = graph.update(); // copy
44909             // if snapping to way - add midpoint there and consider that the target..
44910
44911             if (edge) {
44912               var midpoint = osmNode();
44913               var action = actionAddMidpoint({
44914                 loc: edge.loc,
44915                 edge: [target.nodes[edge.index - 1], target.nodes[edge.index]]
44916               }, midpoint);
44917               testGraph = action(testGraph);
44918               target = midpoint;
44919             } // can we connect to it?
44920
44921
44922             var ids = [entity.id, target.id];
44923             return actionConnect(ids).disabled(testGraph);
44924           }
44925
44926           function hasInvalidGeometry(entity, graph) {
44927             var parents = graph.parentWays(entity);
44928             var i, j, k;
44929
44930             for (i = 0; i < parents.length; i++) {
44931               var parent = parents[i];
44932               var nodes = [];
44933               var activeIndex = null; // which multipolygon ring contains node being dragged
44934               // test any parent multipolygons for valid geometry
44935
44936               var relations = graph.parentRelations(parent);
44937
44938               for (j = 0; j < relations.length; j++) {
44939                 if (!relations[j].isMultipolygon()) continue;
44940                 var rings = osmJoinWays(relations[j].members, graph); // find active ring and test it for self intersections
44941
44942                 for (k = 0; k < rings.length; k++) {
44943                   nodes = rings[k].nodes;
44944
44945                   if (nodes.find(function (n) {
44946                     return n.id === entity.id;
44947                   })) {
44948                     activeIndex = k;
44949
44950                     if (geoHasSelfIntersections(nodes, entity.id)) {
44951                       return 'multipolygonMember';
44952                     }
44953                   }
44954
44955                   rings[k].coords = nodes.map(function (n) {
44956                     return n.loc;
44957                   });
44958                 } // test active ring for intersections with other rings in the multipolygon
44959
44960
44961                 for (k = 0; k < rings.length; k++) {
44962                   if (k === activeIndex) continue; // make sure active ring doesn't cross passive rings
44963
44964                   if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
44965                     return 'multipolygonRing';
44966                   }
44967                 }
44968               } // If we still haven't tested this node's parent way for self-intersections.
44969               // (because it's not a member of a multipolygon), test it now.
44970
44971
44972               if (activeIndex === null) {
44973                 nodes = parent.nodes.map(function (nodeID) {
44974                   return graph.entity(nodeID);
44975                 });
44976
44977                 if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
44978                   return parent.geometry(graph);
44979                 }
44980               }
44981             }
44982
44983             return false;
44984           }
44985
44986           function move(d3_event, entity, point) {
44987             if (_isCancelled) return;
44988             d3_event.stopPropagation();
44989             context.surface().classed('nope-disabled', d3_event.altKey);
44990             _lastLoc = context.projection.invert(point);
44991             doMove(d3_event, entity);
44992             var nudge = geoViewportEdge(point, context.map().dimensions());
44993
44994             if (nudge) {
44995               startNudge(d3_event, entity, nudge);
44996             } else {
44997               stopNudge();
44998             }
44999           }
45000
45001           function end(d3_event, entity) {
45002             if (_isCancelled) return;
45003             var wasPoint = entity.geometry(context.graph()) === 'point';
45004             var d = datum(d3_event);
45005             var nope = d && d.properties && d.properties.nope || context.surface().classed('nope');
45006             var target = d && d.properties && d.properties.entity; // entity to snap to
45007
45008             if (nope) {
45009               // bounce back
45010               context.perform(_actionBounceBack(entity.id, _startLoc));
45011             } else if (target && target.type === 'way') {
45012               var choice = geoChooseEdge(context.graph().childNodes(target), context.map().mouse(), context.projection, entity.id);
45013               context.replace(actionAddMidpoint({
45014                 loc: choice.loc,
45015                 edge: [target.nodes[choice.index - 1], target.nodes[choice.index]]
45016               }, entity), connectAnnotation(entity, target));
45017             } else if (target && target.type === 'node' && shouldSnapToNode(target)) {
45018               context.replace(actionConnect([target.id, entity.id]), connectAnnotation(entity, target));
45019             } else if (_wasMidpoint) {
45020               context.replace(actionNoop(), _t('operations.add.annotation.vertex'));
45021             } else {
45022               context.replace(actionNoop(), moveAnnotation(entity));
45023             }
45024
45025             if (wasPoint) {
45026               context.enter(modeSelect(context, [entity.id]));
45027             } else {
45028               var reselection = _restoreSelectedIDs.filter(function (id) {
45029                 return context.graph().hasEntity(id);
45030               });
45031
45032               if (reselection.length) {
45033                 context.enter(modeSelect(context, reselection));
45034               } else {
45035                 context.enter(modeBrowse(context));
45036               }
45037             }
45038           }
45039
45040           function _actionBounceBack(nodeID, toLoc) {
45041             var moveNode = actionMoveNode(nodeID, toLoc);
45042
45043             var action = function action(graph, t) {
45044               // last time through, pop off the bounceback perform.
45045               // it will then overwrite the initial perform with a moveNode that does nothing
45046               if (t === 1) context.pop();
45047               return moveNode(graph, t);
45048             };
45049
45050             action.transitionable = true;
45051             return action;
45052           }
45053
45054           function cancel() {
45055             drag.cancel();
45056             context.enter(modeBrowse(context));
45057           }
45058
45059           var drag = behaviorDrag().selector('.layer-touch.points .target').surface(context.container().select('.main-map').node()).origin(origin).on('start', start).on('move', move).on('end', end);
45060
45061           mode.enter = function () {
45062             context.install(hover);
45063             context.install(edit);
45064             select(window).on('keydown.dragNode', keydown).on('keyup.dragNode', keyup);
45065             context.history().on('undone.drag-node', cancel);
45066           };
45067
45068           mode.exit = function () {
45069             context.ui().sidebar.hover.cancel();
45070             context.uninstall(hover);
45071             context.uninstall(edit);
45072             select(window).on('keydown.dragNode', null).on('keyup.dragNode', null);
45073             context.history().on('undone.drag-node', null);
45074             _activeEntity = null;
45075             context.surface().classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false).selectAll('.active').classed('active', false);
45076             stopNudge();
45077           };
45078
45079           mode.selectedIDs = function () {
45080             if (!arguments.length) return _activeEntity ? [_activeEntity.id] : []; // no assign
45081
45082             return mode;
45083           };
45084
45085           mode.activeID = function () {
45086             if (!arguments.length) return _activeEntity && _activeEntity.id; // no assign
45087
45088             return mode;
45089           };
45090
45091           mode.restoreSelectedIDs = function (_) {
45092             if (!arguments.length) return _restoreSelectedIDs;
45093             _restoreSelectedIDs = _;
45094             return mode;
45095           };
45096
45097           mode.behavior = drag;
45098           return mode;
45099         }
45100
45101         // Safari bug https://bugs.webkit.org/show_bug.cgi?id=200829
45102         var NON_GENERIC = !!nativePromiseConstructor && fails(function () {
45103           nativePromiseConstructor.prototype['finally'].call({ then: function () { /* empty */ } }, function () { /* empty */ });
45104         });
45105
45106         // `Promise.prototype.finally` method
45107         // https://tc39.es/ecma262/#sec-promise.prototype.finally
45108         _export({ target: 'Promise', proto: true, real: true, forced: NON_GENERIC }, {
45109           'finally': function (onFinally) {
45110             var C = speciesConstructor(this, getBuiltIn('Promise'));
45111             var isFunction = typeof onFinally == 'function';
45112             return this.then(
45113               isFunction ? function (x) {
45114                 return promiseResolve(C, onFinally()).then(function () { return x; });
45115               } : onFinally,
45116               isFunction ? function (e) {
45117                 return promiseResolve(C, onFinally()).then(function () { throw e; });
45118               } : onFinally
45119             );
45120           }
45121         });
45122
45123         // makes sure that native promise-based APIs `Promise#finally` properly works with patched `Promise#then`
45124         if (typeof nativePromiseConstructor == 'function') {
45125           var method = getBuiltIn('Promise').prototype['finally'];
45126           if (nativePromiseConstructor.prototype['finally'] !== method) {
45127             redefine(nativePromiseConstructor.prototype, 'finally', method, { unsafe: true });
45128           }
45129         }
45130
45131         function quickselect(arr, k, left, right, compare) {
45132           quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
45133         }
45134
45135         function quickselectStep(arr, k, left, right, compare) {
45136           while (right > left) {
45137             if (right - left > 600) {
45138               var n = right - left + 1;
45139               var m = k - left + 1;
45140               var z = Math.log(n);
45141               var s = 0.5 * Math.exp(2 * z / 3);
45142               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
45143               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
45144               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
45145               quickselectStep(arr, k, newLeft, newRight, compare);
45146             }
45147
45148             var t = arr[k];
45149             var i = left;
45150             var j = right;
45151             swap(arr, left, k);
45152             if (compare(arr[right], t) > 0) swap(arr, left, right);
45153
45154             while (i < j) {
45155               swap(arr, i, j);
45156               i++;
45157               j--;
45158
45159               while (compare(arr[i], t) < 0) {
45160                 i++;
45161               }
45162
45163               while (compare(arr[j], t) > 0) {
45164                 j--;
45165               }
45166             }
45167
45168             if (compare(arr[left], t) === 0) swap(arr, left, j);else {
45169               j++;
45170               swap(arr, j, right);
45171             }
45172             if (j <= k) left = j + 1;
45173             if (k <= j) right = j - 1;
45174           }
45175         }
45176
45177         function swap(arr, i, j) {
45178           var tmp = arr[i];
45179           arr[i] = arr[j];
45180           arr[j] = tmp;
45181         }
45182
45183         function defaultCompare(a, b) {
45184           return a < b ? -1 : a > b ? 1 : 0;
45185         }
45186
45187         var RBush = /*#__PURE__*/function () {
45188           function RBush() {
45189             var maxEntries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 9;
45190
45191             _classCallCheck$1(this, RBush);
45192
45193             // max entries in a node is 9 by default; min node fill is 40% for best performance
45194             this._maxEntries = Math.max(4, maxEntries);
45195             this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
45196             this.clear();
45197           }
45198
45199           _createClass$1(RBush, [{
45200             key: "all",
45201             value: function all() {
45202               return this._all(this.data, []);
45203             }
45204           }, {
45205             key: "search",
45206             value: function search(bbox) {
45207               var node = this.data;
45208               var result = [];
45209               if (!intersects(bbox, node)) return result;
45210               var toBBox = this.toBBox;
45211               var nodesToSearch = [];
45212
45213               while (node) {
45214                 for (var i = 0; i < node.children.length; i++) {
45215                   var child = node.children[i];
45216                   var childBBox = node.leaf ? toBBox(child) : child;
45217
45218                   if (intersects(bbox, childBBox)) {
45219                     if (node.leaf) result.push(child);else if (contains(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
45220                   }
45221                 }
45222
45223                 node = nodesToSearch.pop();
45224               }
45225
45226               return result;
45227             }
45228           }, {
45229             key: "collides",
45230             value: function collides(bbox) {
45231               var node = this.data;
45232               if (!intersects(bbox, node)) return false;
45233               var nodesToSearch = [];
45234
45235               while (node) {
45236                 for (var i = 0; i < node.children.length; i++) {
45237                   var child = node.children[i];
45238                   var childBBox = node.leaf ? this.toBBox(child) : child;
45239
45240                   if (intersects(bbox, childBBox)) {
45241                     if (node.leaf || contains(bbox, childBBox)) return true;
45242                     nodesToSearch.push(child);
45243                   }
45244                 }
45245
45246                 node = nodesToSearch.pop();
45247               }
45248
45249               return false;
45250             }
45251           }, {
45252             key: "load",
45253             value: function load(data) {
45254               if (!(data && data.length)) return this;
45255
45256               if (data.length < this._minEntries) {
45257                 for (var i = 0; i < data.length; i++) {
45258                   this.insert(data[i]);
45259                 }
45260
45261                 return this;
45262               } // recursively build the tree with the given data from scratch using OMT algorithm
45263
45264
45265               var node = this._build(data.slice(), 0, data.length - 1, 0);
45266
45267               if (!this.data.children.length) {
45268                 // save as is if tree is empty
45269                 this.data = node;
45270               } else if (this.data.height === node.height) {
45271                 // split root if trees have the same height
45272                 this._splitRoot(this.data, node);
45273               } else {
45274                 if (this.data.height < node.height) {
45275                   // swap trees if inserted one is bigger
45276                   var tmpNode = this.data;
45277                   this.data = node;
45278                   node = tmpNode;
45279                 } // insert the small tree into the large tree at appropriate level
45280
45281
45282                 this._insert(node, this.data.height - node.height - 1, true);
45283               }
45284
45285               return this;
45286             }
45287           }, {
45288             key: "insert",
45289             value: function insert(item) {
45290               if (item) this._insert(item, this.data.height - 1);
45291               return this;
45292             }
45293           }, {
45294             key: "clear",
45295             value: function clear() {
45296               this.data = createNode([]);
45297               return this;
45298             }
45299           }, {
45300             key: "remove",
45301             value: function remove(item, equalsFn) {
45302               if (!item) return this;
45303               var node = this.data;
45304               var bbox = this.toBBox(item);
45305               var path = [];
45306               var indexes = [];
45307               var i, parent, goingUp; // depth-first iterative tree traversal
45308
45309               while (node || path.length) {
45310                 if (!node) {
45311                   // go up
45312                   node = path.pop();
45313                   parent = path[path.length - 1];
45314                   i = indexes.pop();
45315                   goingUp = true;
45316                 }
45317
45318                 if (node.leaf) {
45319                   // check current node
45320                   var index = findItem(item, node.children, equalsFn);
45321
45322                   if (index !== -1) {
45323                     // item found, remove the item and condense tree upwards
45324                     node.children.splice(index, 1);
45325                     path.push(node);
45326
45327                     this._condense(path);
45328
45329                     return this;
45330                   }
45331                 }
45332
45333                 if (!goingUp && !node.leaf && contains(node, bbox)) {
45334                   // go down
45335                   path.push(node);
45336                   indexes.push(i);
45337                   i = 0;
45338                   parent = node;
45339                   node = node.children[0];
45340                 } else if (parent) {
45341                   // go right
45342                   i++;
45343                   node = parent.children[i];
45344                   goingUp = false;
45345                 } else node = null; // nothing found
45346
45347               }
45348
45349               return this;
45350             }
45351           }, {
45352             key: "toBBox",
45353             value: function toBBox(item) {
45354               return item;
45355             }
45356           }, {
45357             key: "compareMinX",
45358             value: function compareMinX(a, b) {
45359               return a.minX - b.minX;
45360             }
45361           }, {
45362             key: "compareMinY",
45363             value: function compareMinY(a, b) {
45364               return a.minY - b.minY;
45365             }
45366           }, {
45367             key: "toJSON",
45368             value: function toJSON() {
45369               return this.data;
45370             }
45371           }, {
45372             key: "fromJSON",
45373             value: function fromJSON(data) {
45374               this.data = data;
45375               return this;
45376             }
45377           }, {
45378             key: "_all",
45379             value: function _all(node, result) {
45380               var nodesToSearch = [];
45381
45382               while (node) {
45383                 if (node.leaf) result.push.apply(result, _toConsumableArray(node.children));else nodesToSearch.push.apply(nodesToSearch, _toConsumableArray(node.children));
45384                 node = nodesToSearch.pop();
45385               }
45386
45387               return result;
45388             }
45389           }, {
45390             key: "_build",
45391             value: function _build(items, left, right, height) {
45392               var N = right - left + 1;
45393               var M = this._maxEntries;
45394               var node;
45395
45396               if (N <= M) {
45397                 // reached leaf level; return leaf
45398                 node = createNode(items.slice(left, right + 1));
45399                 calcBBox(node, this.toBBox);
45400                 return node;
45401               }
45402
45403               if (!height) {
45404                 // target height of the bulk-loaded tree
45405                 height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
45406
45407                 M = Math.ceil(N / Math.pow(M, height - 1));
45408               }
45409
45410               node = createNode([]);
45411               node.leaf = false;
45412               node.height = height; // split the items into M mostly square tiles
45413
45414               var N2 = Math.ceil(N / M);
45415               var N1 = N2 * Math.ceil(Math.sqrt(M));
45416               multiSelect(items, left, right, N1, this.compareMinX);
45417
45418               for (var i = left; i <= right; i += N1) {
45419                 var right2 = Math.min(i + N1 - 1, right);
45420                 multiSelect(items, i, right2, N2, this.compareMinY);
45421
45422                 for (var j = i; j <= right2; j += N2) {
45423                   var right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
45424
45425                   node.children.push(this._build(items, j, right3, height - 1));
45426                 }
45427               }
45428
45429               calcBBox(node, this.toBBox);
45430               return node;
45431             }
45432           }, {
45433             key: "_chooseSubtree",
45434             value: function _chooseSubtree(bbox, node, level, path) {
45435               while (true) {
45436                 path.push(node);
45437                 if (node.leaf || path.length - 1 === level) break;
45438                 var minArea = Infinity;
45439                 var minEnlargement = Infinity;
45440                 var targetNode = void 0;
45441
45442                 for (var i = 0; i < node.children.length; i++) {
45443                   var child = node.children[i];
45444                   var area = bboxArea(child);
45445                   var enlargement = enlargedArea(bbox, child) - area; // choose entry with the least area enlargement
45446
45447                   if (enlargement < minEnlargement) {
45448                     minEnlargement = enlargement;
45449                     minArea = area < minArea ? area : minArea;
45450                     targetNode = child;
45451                   } else if (enlargement === minEnlargement) {
45452                     // otherwise choose one with the smallest area
45453                     if (area < minArea) {
45454                       minArea = area;
45455                       targetNode = child;
45456                     }
45457                   }
45458                 }
45459
45460                 node = targetNode || node.children[0];
45461               }
45462
45463               return node;
45464             }
45465           }, {
45466             key: "_insert",
45467             value: function _insert(item, level, isNode) {
45468               var bbox = isNode ? item : this.toBBox(item);
45469               var insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
45470
45471               var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
45472
45473
45474               node.children.push(item);
45475               extend$1(node, bbox); // split on node overflow; propagate upwards if necessary
45476
45477               while (level >= 0) {
45478                 if (insertPath[level].children.length > this._maxEntries) {
45479                   this._split(insertPath, level);
45480
45481                   level--;
45482                 } else break;
45483               } // adjust bboxes along the insertion path
45484
45485
45486               this._adjustParentBBoxes(bbox, insertPath, level);
45487             } // split overflowed node into two
45488
45489           }, {
45490             key: "_split",
45491             value: function _split(insertPath, level) {
45492               var node = insertPath[level];
45493               var M = node.children.length;
45494               var m = this._minEntries;
45495
45496               this._chooseSplitAxis(node, m, M);
45497
45498               var splitIndex = this._chooseSplitIndex(node, m, M);
45499
45500               var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
45501               newNode.height = node.height;
45502               newNode.leaf = node.leaf;
45503               calcBBox(node, this.toBBox);
45504               calcBBox(newNode, this.toBBox);
45505               if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
45506             }
45507           }, {
45508             key: "_splitRoot",
45509             value: function _splitRoot(node, newNode) {
45510               // split root node
45511               this.data = createNode([node, newNode]);
45512               this.data.height = node.height + 1;
45513               this.data.leaf = false;
45514               calcBBox(this.data, this.toBBox);
45515             }
45516           }, {
45517             key: "_chooseSplitIndex",
45518             value: function _chooseSplitIndex(node, m, M) {
45519               var index;
45520               var minOverlap = Infinity;
45521               var minArea = Infinity;
45522
45523               for (var i = m; i <= M - m; i++) {
45524                 var bbox1 = distBBox(node, 0, i, this.toBBox);
45525                 var bbox2 = distBBox(node, i, M, this.toBBox);
45526                 var overlap = intersectionArea(bbox1, bbox2);
45527                 var area = bboxArea(bbox1) + bboxArea(bbox2); // choose distribution with minimum overlap
45528
45529                 if (overlap < minOverlap) {
45530                   minOverlap = overlap;
45531                   index = i;
45532                   minArea = area < minArea ? area : minArea;
45533                 } else if (overlap === minOverlap) {
45534                   // otherwise choose distribution with minimum area
45535                   if (area < minArea) {
45536                     minArea = area;
45537                     index = i;
45538                   }
45539                 }
45540               }
45541
45542               return index || M - m;
45543             } // sorts node children by the best axis for split
45544
45545           }, {
45546             key: "_chooseSplitAxis",
45547             value: function _chooseSplitAxis(node, m, M) {
45548               var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
45549               var compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
45550
45551               var xMargin = this._allDistMargin(node, m, M, compareMinX);
45552
45553               var yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
45554               // otherwise it's already sorted by minY
45555
45556
45557               if (xMargin < yMargin) node.children.sort(compareMinX);
45558             } // total margin of all possible split distributions where each node is at least m full
45559
45560           }, {
45561             key: "_allDistMargin",
45562             value: function _allDistMargin(node, m, M, compare) {
45563               node.children.sort(compare);
45564               var toBBox = this.toBBox;
45565               var leftBBox = distBBox(node, 0, m, toBBox);
45566               var rightBBox = distBBox(node, M - m, M, toBBox);
45567               var margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
45568
45569               for (var i = m; i < M - m; i++) {
45570                 var child = node.children[i];
45571                 extend$1(leftBBox, node.leaf ? toBBox(child) : child);
45572                 margin += bboxMargin(leftBBox);
45573               }
45574
45575               for (var _i = M - m - 1; _i >= m; _i--) {
45576                 var _child = node.children[_i];
45577                 extend$1(rightBBox, node.leaf ? toBBox(_child) : _child);
45578                 margin += bboxMargin(rightBBox);
45579               }
45580
45581               return margin;
45582             }
45583           }, {
45584             key: "_adjustParentBBoxes",
45585             value: function _adjustParentBBoxes(bbox, path, level) {
45586               // adjust bboxes along the given tree path
45587               for (var i = level; i >= 0; i--) {
45588                 extend$1(path[i], bbox);
45589               }
45590             }
45591           }, {
45592             key: "_condense",
45593             value: function _condense(path) {
45594               // go through the path, removing empty nodes and updating bboxes
45595               for (var i = path.length - 1, siblings; i >= 0; i--) {
45596                 if (path[i].children.length === 0) {
45597                   if (i > 0) {
45598                     siblings = path[i - 1].children;
45599                     siblings.splice(siblings.indexOf(path[i]), 1);
45600                   } else this.clear();
45601                 } else calcBBox(path[i], this.toBBox);
45602               }
45603             }
45604           }]);
45605
45606           return RBush;
45607         }();
45608
45609         function findItem(item, items, equalsFn) {
45610           if (!equalsFn) return items.indexOf(item);
45611
45612           for (var i = 0; i < items.length; i++) {
45613             if (equalsFn(item, items[i])) return i;
45614           }
45615
45616           return -1;
45617         } // calculate node's bbox from bboxes of its children
45618
45619
45620         function calcBBox(node, toBBox) {
45621           distBBox(node, 0, node.children.length, toBBox, node);
45622         } // min bounding rectangle of node children from k to p-1
45623
45624
45625         function distBBox(node, k, p, toBBox, destNode) {
45626           if (!destNode) destNode = createNode(null);
45627           destNode.minX = Infinity;
45628           destNode.minY = Infinity;
45629           destNode.maxX = -Infinity;
45630           destNode.maxY = -Infinity;
45631
45632           for (var i = k; i < p; i++) {
45633             var child = node.children[i];
45634             extend$1(destNode, node.leaf ? toBBox(child) : child);
45635           }
45636
45637           return destNode;
45638         }
45639
45640         function extend$1(a, b) {
45641           a.minX = Math.min(a.minX, b.minX);
45642           a.minY = Math.min(a.minY, b.minY);
45643           a.maxX = Math.max(a.maxX, b.maxX);
45644           a.maxY = Math.max(a.maxY, b.maxY);
45645           return a;
45646         }
45647
45648         function compareNodeMinX(a, b) {
45649           return a.minX - b.minX;
45650         }
45651
45652         function compareNodeMinY(a, b) {
45653           return a.minY - b.minY;
45654         }
45655
45656         function bboxArea(a) {
45657           return (a.maxX - a.minX) * (a.maxY - a.minY);
45658         }
45659
45660         function bboxMargin(a) {
45661           return a.maxX - a.minX + (a.maxY - a.minY);
45662         }
45663
45664         function enlargedArea(a, b) {
45665           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));
45666         }
45667
45668         function intersectionArea(a, b) {
45669           var minX = Math.max(a.minX, b.minX);
45670           var minY = Math.max(a.minY, b.minY);
45671           var maxX = Math.min(a.maxX, b.maxX);
45672           var maxY = Math.min(a.maxY, b.maxY);
45673           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
45674         }
45675
45676         function contains(a, b) {
45677           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
45678         }
45679
45680         function intersects(a, b) {
45681           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
45682         }
45683
45684         function createNode(children) {
45685           return {
45686             children: children,
45687             height: 1,
45688             leaf: true,
45689             minX: Infinity,
45690             minY: Infinity,
45691             maxX: -Infinity,
45692             maxY: -Infinity
45693           };
45694         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
45695         // combines selection algorithm with binary divide & conquer approach
45696
45697
45698         function multiSelect(arr, left, right, n, compare) {
45699           var stack = [left, right];
45700
45701           while (stack.length) {
45702             right = stack.pop();
45703             left = stack.pop();
45704             if (right - left <= n) continue;
45705             var mid = left + Math.ceil((right - left) / n / 2) * n;
45706             quickselect(arr, mid, left, right, compare);
45707             stack.push(left, mid, mid, right);
45708           }
45709         }
45710
45711         function responseText(response) {
45712           if (!response.ok) throw new Error(response.status + " " + response.statusText);
45713           return response.text();
45714         }
45715
45716         function d3_text (input, init) {
45717           return fetch(input, init).then(responseText);
45718         }
45719
45720         function responseJson(response) {
45721           if (!response.ok) throw new Error(response.status + " " + response.statusText);
45722           if (response.status === 204 || response.status === 205) return;
45723           return response.json();
45724         }
45725
45726         function d3_json (input, init) {
45727           return fetch(input, init).then(responseJson);
45728         }
45729
45730         function parser(type) {
45731           return function (input, init) {
45732             return d3_text(input, init).then(function (text) {
45733               return new DOMParser().parseFromString(text, type);
45734             });
45735           };
45736         }
45737
45738         var d3_xml = parser("application/xml");
45739         var svg = parser("image/svg+xml");
45740
45741         var tiler$6 = utilTiler();
45742         var dispatch$7 = dispatch$8('loaded');
45743         var _tileZoom$3 = 14;
45744         var _krUrlRoot = 'https://www.keepright.at';
45745         var _krData = {
45746           errorTypes: {},
45747           localizeStrings: {}
45748         }; // This gets reassigned if reset
45749
45750         var _cache$2;
45751
45752         var _krRuleset = [// no 20 - multiple node on same spot - these are mostly boundaries overlapping roads
45753         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];
45754
45755         function abortRequest$6(controller) {
45756           if (controller) {
45757             controller.abort();
45758           }
45759         }
45760
45761         function abortUnwantedRequests$3(cache, tiles) {
45762           Object.keys(cache.inflightTile).forEach(function (k) {
45763             var wanted = tiles.find(function (tile) {
45764               return k === tile.id;
45765             });
45766
45767             if (!wanted) {
45768               abortRequest$6(cache.inflightTile[k]);
45769               delete cache.inflightTile[k];
45770             }
45771           });
45772         }
45773
45774         function encodeIssueRtree$2(d) {
45775           return {
45776             minX: d.loc[0],
45777             minY: d.loc[1],
45778             maxX: d.loc[0],
45779             maxY: d.loc[1],
45780             data: d
45781           };
45782         } // Replace or remove QAItem from rtree
45783
45784
45785         function updateRtree$3(item, replace) {
45786           _cache$2.rtree.remove(item, function (a, b) {
45787             return a.data.id === b.data.id;
45788           });
45789
45790           if (replace) {
45791             _cache$2.rtree.insert(item);
45792           }
45793         }
45794
45795         function tokenReplacements(d) {
45796           if (!(d instanceof QAItem)) return;
45797           var htmlRegex = new RegExp(/<\/[a-z][\s\S]*>/);
45798           var replacements = {};
45799           var issueTemplate = _krData.errorTypes[d.whichType];
45800
45801           if (!issueTemplate) {
45802             /* eslint-disable no-console */
45803             console.log('No Template: ', d.whichType);
45804             console.log('  ', d.description);
45805             /* eslint-enable no-console */
45806
45807             return;
45808           } // some descriptions are just fixed text
45809
45810
45811           if (!issueTemplate.regex) return; // regex pattern should match description with variable details captured
45812
45813           var errorRegex = new RegExp(issueTemplate.regex, 'i');
45814           var errorMatch = errorRegex.exec(d.description);
45815
45816           if (!errorMatch) {
45817             /* eslint-disable no-console */
45818             console.log('Unmatched: ', d.whichType);
45819             console.log('  ', d.description);
45820             console.log('  ', errorRegex);
45821             /* eslint-enable no-console */
45822
45823             return;
45824           }
45825
45826           for (var i = 1; i < errorMatch.length; i++) {
45827             // skip first
45828             var capture = errorMatch[i];
45829             var idType = void 0;
45830             idType = 'IDs' in issueTemplate ? issueTemplate.IDs[i - 1] : '';
45831
45832             if (idType && capture) {
45833               // link IDs if present in the capture
45834               capture = parseError(capture, idType);
45835             } else if (htmlRegex.test(capture)) {
45836               // escape any html in non-IDs
45837               capture = '\\' + capture + '\\';
45838             } else {
45839               var compare = capture.toLowerCase();
45840
45841               if (_krData.localizeStrings[compare]) {
45842                 // some replacement strings can be localized
45843                 capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
45844               }
45845             }
45846
45847             replacements['var' + i] = capture;
45848           }
45849
45850           return replacements;
45851         }
45852
45853         function parseError(capture, idType) {
45854           var compare = capture.toLowerCase();
45855
45856           if (_krData.localizeStrings[compare]) {
45857             // some replacement strings can be localized
45858             capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
45859           }
45860
45861           switch (idType) {
45862             // link a string like "this node"
45863             case 'this':
45864               capture = linkErrorObject(capture);
45865               break;
45866
45867             case 'url':
45868               capture = linkURL(capture);
45869               break;
45870             // link an entity ID
45871
45872             case 'n':
45873             case 'w':
45874             case 'r':
45875               capture = linkEntity(idType + capture);
45876               break;
45877             // some errors have more complex ID lists/variance
45878
45879             case '20':
45880               capture = parse20(capture);
45881               break;
45882
45883             case '211':
45884               capture = parse211(capture);
45885               break;
45886
45887             case '231':
45888               capture = parse231(capture);
45889               break;
45890
45891             case '294':
45892               capture = parse294(capture);
45893               break;
45894
45895             case '370':
45896               capture = parse370(capture);
45897               break;
45898           }
45899
45900           return capture;
45901
45902           function linkErrorObject(d) {
45903             return "<a class=\"error_object_link\">".concat(d, "</a>");
45904           }
45905
45906           function linkEntity(d) {
45907             return "<a class=\"error_entity_link\">".concat(d, "</a>");
45908           }
45909
45910           function linkURL(d) {
45911             return "<a class=\"kr_external_link\" target=\"_blank\" href=\"".concat(d, "\">").concat(d, "</a>");
45912           } // arbitrary node list of form: #ID, #ID, #ID...
45913
45914
45915           function parse211(capture) {
45916             var newList = [];
45917             var items = capture.split(', ');
45918             items.forEach(function (item) {
45919               // ID has # at the front
45920               var id = linkEntity('n' + item.slice(1));
45921               newList.push(id);
45922             });
45923             return newList.join(', ');
45924           } // arbitrary way list of form: #ID(layer),#ID(layer),#ID(layer)...
45925
45926
45927           function parse231(capture) {
45928             var newList = []; // unfortunately 'layer' can itself contain commas, so we split on '),'
45929
45930             var items = capture.split('),');
45931             items.forEach(function (item) {
45932               var match = item.match(/\#(\d+)\((.+)\)?/);
45933
45934               if (match !== null && match.length > 2) {
45935                 newList.push(linkEntity('w' + match[1]) + ' ' + _t('QA.keepRight.errorTypes.231.layer', {
45936                   layer: match[2]
45937                 }));
45938               }
45939             });
45940             return newList.join(', ');
45941           } // arbitrary node/relation list of form: from node #ID,to relation #ID,to node #ID...
45942
45943
45944           function parse294(capture) {
45945             var newList = [];
45946             var items = capture.split(',');
45947             items.forEach(function (item) {
45948               // item of form "from/to node/relation #ID"
45949               item = item.split(' '); // to/from role is more clear in quotes
45950
45951               var role = "\"".concat(item[0], "\""); // first letter of node/relation provides the type
45952
45953               var idType = item[1].slice(0, 1); // ID has # at the front
45954
45955               var id = item[2].slice(1);
45956               id = linkEntity(idType + id);
45957               newList.push("".concat(role, " ").concat(item[1], " ").concat(id));
45958             });
45959             return newList.join(', ');
45960           } // may or may not include the string "(including the name 'name')"
45961
45962
45963           function parse370(capture) {
45964             if (!capture) return '';
45965             var match = capture.match(/\(including the name (\'.+\')\)/);
45966
45967             if (match && match.length) {
45968               return _t('QA.keepRight.errorTypes.370.including_the_name', {
45969                 name: match[1]
45970               });
45971             }
45972
45973             return '';
45974           } // arbitrary node list of form: #ID,#ID,#ID...
45975
45976
45977           function parse20(capture) {
45978             var newList = [];
45979             var items = capture.split(',');
45980             items.forEach(function (item) {
45981               // ID has # at the front
45982               var id = linkEntity('n' + item.slice(1));
45983               newList.push(id);
45984             });
45985             return newList.join(', ');
45986           }
45987         }
45988
45989         var serviceKeepRight = {
45990           title: 'keepRight',
45991           init: function init() {
45992             _mainFileFetcher.get('keepRight').then(function (d) {
45993               return _krData = d;
45994             });
45995
45996             if (!_cache$2) {
45997               this.reset();
45998             }
45999
46000             this.event = utilRebind(this, dispatch$7, 'on');
46001           },
46002           reset: function reset() {
46003             if (_cache$2) {
46004               Object.values(_cache$2.inflightTile).forEach(abortRequest$6);
46005             }
46006
46007             _cache$2 = {
46008               data: {},
46009               loadedTile: {},
46010               inflightTile: {},
46011               inflightPost: {},
46012               closed: {},
46013               rtree: new RBush()
46014             };
46015           },
46016           // KeepRight API:  http://osm.mueschelsoft.de/keepright/interfacing.php
46017           loadIssues: function loadIssues(projection) {
46018             var _this = this;
46019
46020             var options = {
46021               format: 'geojson',
46022               ch: _krRuleset
46023             }; // determine the needed tiles to cover the view
46024
46025             var tiles = tiler$6.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection); // abort inflight requests that are no longer needed
46026
46027             abortUnwantedRequests$3(_cache$2, tiles); // issue new requests..
46028
46029             tiles.forEach(function (tile) {
46030               if (_cache$2.loadedTile[tile.id] || _cache$2.inflightTile[tile.id]) return;
46031
46032               var _tile$extent$rectangl = tile.extent.rectangle(),
46033                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
46034                   left = _tile$extent$rectangl2[0],
46035                   top = _tile$extent$rectangl2[1],
46036                   right = _tile$extent$rectangl2[2],
46037                   bottom = _tile$extent$rectangl2[3];
46038
46039               var params = Object.assign({}, options, {
46040                 left: left,
46041                 bottom: bottom,
46042                 right: right,
46043                 top: top
46044               });
46045               var url = "".concat(_krUrlRoot, "/export.php?") + utilQsString(params);
46046               var controller = new AbortController();
46047               _cache$2.inflightTile[tile.id] = controller;
46048               d3_json(url, {
46049                 signal: controller.signal
46050               }).then(function (data) {
46051                 delete _cache$2.inflightTile[tile.id];
46052                 _cache$2.loadedTile[tile.id] = true;
46053
46054                 if (!data || !data.features || !data.features.length) {
46055                   throw new Error('No Data');
46056                 }
46057
46058                 data.features.forEach(function (feature) {
46059                   var _feature$properties = feature.properties,
46060                       itemType = _feature$properties.error_type,
46061                       id = _feature$properties.error_id,
46062                       _feature$properties$c = _feature$properties.comment,
46063                       comment = _feature$properties$c === void 0 ? null : _feature$properties$c,
46064                       objectId = _feature$properties.object_id,
46065                       objectType = _feature$properties.object_type,
46066                       schema = _feature$properties.schema,
46067                       title = _feature$properties.title;
46068                   var loc = feature.geometry.coordinates,
46069                       _feature$properties$d = feature.properties.description,
46070                       description = _feature$properties$d === void 0 ? '' : _feature$properties$d; // if there is a parent, save its error type e.g.:
46071                   //  Error 191 = "highway-highway"
46072                   //  Error 190 = "intersections without junctions"  (parent)
46073
46074                   var issueTemplate = _krData.errorTypes[itemType];
46075                   var parentIssueType = (Math.floor(itemType / 10) * 10).toString(); // try to handle error type directly, fallback to parent error type.
46076
46077                   var whichType = issueTemplate ? itemType : parentIssueType;
46078                   var whichTemplate = _krData.errorTypes[whichType]; // Rewrite a few of the errors at this point..
46079                   // This is done to make them easier to linkify and translate.
46080
46081                   switch (whichType) {
46082                     case '170':
46083                       description = "This feature has a FIXME tag: ".concat(description);
46084                       break;
46085
46086                     case '292':
46087                     case '293':
46088                       description = description.replace('A turn-', 'This turn-');
46089                       break;
46090
46091                     case '294':
46092                     case '295':
46093                     case '296':
46094                     case '297':
46095                     case '298':
46096                       description = "This turn-restriction~".concat(description);
46097                       break;
46098
46099                     case '300':
46100                       description = 'This highway is missing a maxspeed tag';
46101                       break;
46102
46103                     case '411':
46104                     case '412':
46105                     case '413':
46106                       description = "This feature~".concat(description);
46107                       break;
46108                   } // move markers slightly so it doesn't obscure the geometry,
46109                   // then move markers away from other coincident markers
46110
46111
46112                   var coincident = false;
46113
46114                   do {
46115                     // first time, move marker up. after that, move marker right.
46116                     var delta = coincident ? [0.00001, 0] : [0, 0.00001];
46117                     loc = geoVecAdd(loc, delta);
46118                     var bbox = geoExtent(loc).bbox();
46119                     coincident = _cache$2.rtree.search(bbox).length;
46120                   } while (coincident);
46121
46122                   var d = new QAItem(loc, _this, itemType, id, {
46123                     comment: comment,
46124                     description: description,
46125                     whichType: whichType,
46126                     parentIssueType: parentIssueType,
46127                     severity: whichTemplate.severity || 'error',
46128                     objectId: objectId,
46129                     objectType: objectType,
46130                     schema: schema,
46131                     title: title
46132                   });
46133                   d.replacements = tokenReplacements(d);
46134                   _cache$2.data[id] = d;
46135
46136                   _cache$2.rtree.insert(encodeIssueRtree$2(d));
46137                 });
46138                 dispatch$7.call('loaded');
46139               })["catch"](function () {
46140                 delete _cache$2.inflightTile[tile.id];
46141                 _cache$2.loadedTile[tile.id] = true;
46142               });
46143             });
46144           },
46145           postUpdate: function postUpdate(d, callback) {
46146             var _this2 = this;
46147
46148             if (_cache$2.inflightPost[d.id]) {
46149               return callback({
46150                 message: 'Error update already inflight',
46151                 status: -2
46152               }, d);
46153             }
46154
46155             var params = {
46156               schema: d.schema,
46157               id: d.id
46158             };
46159
46160             if (d.newStatus) {
46161               params.st = d.newStatus;
46162             }
46163
46164             if (d.newComment !== undefined) {
46165               params.co = d.newComment;
46166             } // NOTE: This throws a CORS err, but it seems successful.
46167             // We don't care too much about the response, so this is fine.
46168
46169
46170             var url = "".concat(_krUrlRoot, "/comment.php?") + utilQsString(params);
46171             var controller = new AbortController();
46172             _cache$2.inflightPost[d.id] = controller; // Since this is expected to throw an error just continue as if it worked
46173             // (worst case scenario the request truly fails and issue will show up if iD restarts)
46174
46175             d3_json(url, {
46176               signal: controller.signal
46177             })["finally"](function () {
46178               delete _cache$2.inflightPost[d.id];
46179
46180               if (d.newStatus === 'ignore') {
46181                 // ignore permanently (false positive)
46182                 _this2.removeItem(d);
46183               } else if (d.newStatus === 'ignore_t') {
46184                 // ignore temporarily (error fixed)
46185                 _this2.removeItem(d);
46186
46187                 _cache$2.closed["".concat(d.schema, ":").concat(d.id)] = true;
46188               } else {
46189                 d = _this2.replaceItem(d.update({
46190                   comment: d.newComment,
46191                   newComment: undefined,
46192                   newState: undefined
46193                 }));
46194               }
46195
46196               if (callback) callback(null, d);
46197             });
46198           },
46199           // Get all cached QAItems covering the viewport
46200           getItems: function getItems(projection) {
46201             var viewport = projection.clipExtent();
46202             var min = [viewport[0][0], viewport[1][1]];
46203             var max = [viewport[1][0], viewport[0][1]];
46204             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
46205             return _cache$2.rtree.search(bbox).map(function (d) {
46206               return d.data;
46207             });
46208           },
46209           // Get a QAItem from cache
46210           // NOTE: Don't change method name until UI v3 is merged
46211           getError: function getError(id) {
46212             return _cache$2.data[id];
46213           },
46214           // Replace a single QAItem in the cache
46215           replaceItem: function replaceItem(item) {
46216             if (!(item instanceof QAItem) || !item.id) return;
46217             _cache$2.data[item.id] = item;
46218             updateRtree$3(encodeIssueRtree$2(item), true); // true = replace
46219
46220             return item;
46221           },
46222           // Remove a single QAItem from the cache
46223           removeItem: function removeItem(item) {
46224             if (!(item instanceof QAItem) || !item.id) return;
46225             delete _cache$2.data[item.id];
46226             updateRtree$3(encodeIssueRtree$2(item), false); // false = remove
46227           },
46228           issueURL: function issueURL(item) {
46229             return "".concat(_krUrlRoot, "/report_map.php?schema=").concat(item.schema, "&error=").concat(item.id);
46230           },
46231           // Get an array of issues closed during this session.
46232           // Used to populate `closed:keepright` changeset tag
46233           getClosedIDs: function getClosedIDs() {
46234             return Object.keys(_cache$2.closed).sort();
46235           }
46236         };
46237
46238         var tiler$5 = utilTiler();
46239         var dispatch$6 = dispatch$8('loaded');
46240         var _tileZoom$2 = 14;
46241         var _impOsmUrls = {
46242           ow: 'https://grab.community.improve-osm.org/directionOfFlowService',
46243           mr: 'https://grab.community.improve-osm.org/missingGeoService',
46244           tr: 'https://grab.community.improve-osm.org/turnRestrictionService'
46245         };
46246         var _impOsmData = {
46247           icons: {}
46248         }; // This gets reassigned if reset
46249
46250         var _cache$1;
46251
46252         function abortRequest$5(i) {
46253           Object.values(i).forEach(function (controller) {
46254             if (controller) {
46255               controller.abort();
46256             }
46257           });
46258         }
46259
46260         function abortUnwantedRequests$2(cache, tiles) {
46261           Object.keys(cache.inflightTile).forEach(function (k) {
46262             var wanted = tiles.find(function (tile) {
46263               return k === tile.id;
46264             });
46265
46266             if (!wanted) {
46267               abortRequest$5(cache.inflightTile[k]);
46268               delete cache.inflightTile[k];
46269             }
46270           });
46271         }
46272
46273         function encodeIssueRtree$1(d) {
46274           return {
46275             minX: d.loc[0],
46276             minY: d.loc[1],
46277             maxX: d.loc[0],
46278             maxY: d.loc[1],
46279             data: d
46280           };
46281         } // Replace or remove QAItem from rtree
46282
46283
46284         function updateRtree$2(item, replace) {
46285           _cache$1.rtree.remove(item, function (a, b) {
46286             return a.data.id === b.data.id;
46287           });
46288
46289           if (replace) {
46290             _cache$1.rtree.insert(item);
46291           }
46292         }
46293
46294         function linkErrorObject(d) {
46295           return "<a class=\"error_object_link\">".concat(d, "</a>");
46296         }
46297
46298         function linkEntity(d) {
46299           return "<a class=\"error_entity_link\">".concat(d, "</a>");
46300         }
46301
46302         function pointAverage(points) {
46303           if (points.length) {
46304             var sum = points.reduce(function (acc, point) {
46305               return geoVecAdd(acc, [point.lon, point.lat]);
46306             }, [0, 0]);
46307             return geoVecScale(sum, 1 / points.length);
46308           } else {
46309             return [0, 0];
46310           }
46311         }
46312
46313         function relativeBearing(p1, p2) {
46314           var angle = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
46315
46316           if (angle < 0) {
46317             angle += 2 * Math.PI;
46318           } // Return degrees
46319
46320
46321           return angle * 180 / Math.PI;
46322         } // Assuming range [0,360)
46323
46324
46325         function cardinalDirection(bearing) {
46326           var dir = 45 * Math.round(bearing / 45);
46327           var compass = {
46328             0: 'north',
46329             45: 'northeast',
46330             90: 'east',
46331             135: 'southeast',
46332             180: 'south',
46333             225: 'southwest',
46334             270: 'west',
46335             315: 'northwest',
46336             360: 'north'
46337           };
46338           return _t("QA.improveOSM.directions.".concat(compass[dir]));
46339         } // Errors shouldn't obscure each other
46340
46341
46342         function preventCoincident$1(loc, bumpUp) {
46343           var coincident = false;
46344
46345           do {
46346             // first time, move marker up. after that, move marker right.
46347             var delta = coincident ? [0.00001, 0] : bumpUp ? [0, 0.00001] : [0, 0];
46348             loc = geoVecAdd(loc, delta);
46349             var bbox = geoExtent(loc).bbox();
46350             coincident = _cache$1.rtree.search(bbox).length;
46351           } while (coincident);
46352
46353           return loc;
46354         }
46355
46356         var serviceImproveOSM = {
46357           title: 'improveOSM',
46358           init: function init() {
46359             _mainFileFetcher.get('qa_data').then(function (d) {
46360               return _impOsmData = d.improveOSM;
46361             });
46362
46363             if (!_cache$1) {
46364               this.reset();
46365             }
46366
46367             this.event = utilRebind(this, dispatch$6, 'on');
46368           },
46369           reset: function reset() {
46370             if (_cache$1) {
46371               Object.values(_cache$1.inflightTile).forEach(abortRequest$5);
46372             }
46373
46374             _cache$1 = {
46375               data: {},
46376               loadedTile: {},
46377               inflightTile: {},
46378               inflightPost: {},
46379               closed: {},
46380               rtree: new RBush()
46381             };
46382           },
46383           loadIssues: function loadIssues(projection) {
46384             var _this = this;
46385
46386             var options = {
46387               client: 'iD',
46388               status: 'OPEN',
46389               zoom: '19' // Use a high zoom so that clusters aren't returned
46390
46391             }; // determine the needed tiles to cover the view
46392
46393             var tiles = tiler$5.zoomExtent([_tileZoom$2, _tileZoom$2]).getTiles(projection); // abort inflight requests that are no longer needed
46394
46395             abortUnwantedRequests$2(_cache$1, tiles); // issue new requests..
46396
46397             tiles.forEach(function (tile) {
46398               if (_cache$1.loadedTile[tile.id] || _cache$1.inflightTile[tile.id]) return;
46399
46400               var _tile$extent$rectangl = tile.extent.rectangle(),
46401                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
46402                   east = _tile$extent$rectangl2[0],
46403                   north = _tile$extent$rectangl2[1],
46404                   west = _tile$extent$rectangl2[2],
46405                   south = _tile$extent$rectangl2[3];
46406
46407               var params = Object.assign({}, options, {
46408                 east: east,
46409                 south: south,
46410                 west: west,
46411                 north: north
46412               }); // 3 separate requests to store for each tile
46413
46414               var requests = {};
46415               Object.keys(_impOsmUrls).forEach(function (k) {
46416                 // We exclude WATER from missing geometry as it doesn't seem useful
46417                 // We use most confident one-way and turn restrictions only, still have false positives
46418                 var kParams = Object.assign({}, params, k === 'mr' ? {
46419                   type: 'PARKING,ROAD,BOTH,PATH'
46420                 } : {
46421                   confidenceLevel: 'C1'
46422                 });
46423                 var url = "".concat(_impOsmUrls[k], "/search?") + utilQsString(kParams);
46424                 var controller = new AbortController();
46425                 requests[k] = controller;
46426                 d3_json(url, {
46427                   signal: controller.signal
46428                 }).then(function (data) {
46429                   delete _cache$1.inflightTile[tile.id][k];
46430
46431                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
46432                     delete _cache$1.inflightTile[tile.id];
46433                     _cache$1.loadedTile[tile.id] = true;
46434                   } // Road segments at high zoom == oneways
46435
46436
46437                   if (data.roadSegments) {
46438                     data.roadSegments.forEach(function (feature) {
46439                       // Position error at the approximate middle of the segment
46440                       var points = feature.points,
46441                           wayId = feature.wayId,
46442                           fromNodeId = feature.fromNodeId,
46443                           toNodeId = feature.toNodeId;
46444                       var itemId = "".concat(wayId).concat(fromNodeId).concat(toNodeId);
46445                       var mid = points.length / 2;
46446                       var loc; // Even number of points, find midpoint of the middle two
46447                       // Odd number of points, use position of very middle point
46448
46449                       if (mid % 1 === 0) {
46450                         loc = pointAverage([points[mid - 1], points[mid]]);
46451                       } else {
46452                         mid = points[Math.floor(mid)];
46453                         loc = [mid.lon, mid.lat];
46454                       } // One-ways can land on same segment in opposite direction
46455
46456
46457                       loc = preventCoincident$1(loc, false);
46458                       var d = new QAItem(loc, _this, k, itemId, {
46459                         issueKey: k,
46460                         // used as a category
46461                         identifier: {
46462                           // used to post changes
46463                           wayId: wayId,
46464                           fromNodeId: fromNodeId,
46465                           toNodeId: toNodeId
46466                         },
46467                         objectId: wayId,
46468                         objectType: 'way'
46469                       }); // Variables used in the description
46470
46471                       d.replacements = {
46472                         percentage: feature.percentOfTrips,
46473                         num_trips: feature.numberOfTrips,
46474                         highway: linkErrorObject(_t('QA.keepRight.error_parts.highway')),
46475                         from_node: linkEntity('n' + feature.fromNodeId),
46476                         to_node: linkEntity('n' + feature.toNodeId)
46477                       };
46478                       _cache$1.data[d.id] = d;
46479
46480                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
46481                     });
46482                   } // Tiles at high zoom == missing roads
46483
46484
46485                   if (data.tiles) {
46486                     data.tiles.forEach(function (feature) {
46487                       var type = feature.type,
46488                           x = feature.x,
46489                           y = feature.y,
46490                           numberOfTrips = feature.numberOfTrips;
46491                       var geoType = type.toLowerCase();
46492                       var itemId = "".concat(geoType).concat(x).concat(y).concat(numberOfTrips); // Average of recorded points should land on the missing geometry
46493                       // Missing geometry could happen to land on another error
46494
46495                       var loc = pointAverage(feature.points);
46496                       loc = preventCoincident$1(loc, false);
46497                       var d = new QAItem(loc, _this, "".concat(k, "-").concat(geoType), itemId, {
46498                         issueKey: k,
46499                         identifier: {
46500                           x: x,
46501                           y: y
46502                         }
46503                       });
46504                       d.replacements = {
46505                         num_trips: numberOfTrips,
46506                         geometry_type: _t("QA.improveOSM.geometry_types.".concat(geoType))
46507                       }; // -1 trips indicates data came from a 3rd party
46508
46509                       if (numberOfTrips === -1) {
46510                         d.desc = _t('QA.improveOSM.error_types.mr.description_alt', d.replacements);
46511                       }
46512
46513                       _cache$1.data[d.id] = d;
46514
46515                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
46516                     });
46517                   } // Entities at high zoom == turn restrictions
46518
46519
46520                   if (data.entities) {
46521                     data.entities.forEach(function (feature) {
46522                       var point = feature.point,
46523                           id = feature.id,
46524                           segments = feature.segments,
46525                           numberOfPasses = feature.numberOfPasses,
46526                           turnType = feature.turnType;
46527                       var itemId = "".concat(id.replace(/[,:+#]/g, '_')); // Turn restrictions could be missing at same junction
46528                       // We also want to bump the error up so node is accessible
46529
46530                       var loc = preventCoincident$1([point.lon, point.lat], true); // Elements are presented in a strange way
46531
46532                       var ids = id.split(',');
46533                       var from_way = ids[0];
46534                       var via_node = ids[3];
46535                       var to_way = ids[2].split(':')[1];
46536                       var d = new QAItem(loc, _this, k, itemId, {
46537                         issueKey: k,
46538                         identifier: id,
46539                         objectId: via_node,
46540                         objectType: 'node'
46541                       }); // Travel direction along from_way clarifies the turn restriction
46542
46543                       var _segments$0$points = _slicedToArray(segments[0].points, 2),
46544                           p1 = _segments$0$points[0],
46545                           p2 = _segments$0$points[1];
46546
46547                       var dir_of_travel = cardinalDirection(relativeBearing(p1, p2)); // Variables used in the description
46548
46549                       d.replacements = {
46550                         num_passed: numberOfPasses,
46551                         num_trips: segments[0].numberOfTrips,
46552                         turn_restriction: turnType.toLowerCase(),
46553                         from_way: linkEntity('w' + from_way),
46554                         to_way: linkEntity('w' + to_way),
46555                         travel_direction: dir_of_travel,
46556                         junction: linkErrorObject(_t('QA.keepRight.error_parts.this_node'))
46557                       };
46558                       _cache$1.data[d.id] = d;
46559
46560                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
46561
46562                       dispatch$6.call('loaded');
46563                     });
46564                   }
46565                 })["catch"](function () {
46566                   delete _cache$1.inflightTile[tile.id][k];
46567
46568                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
46569                     delete _cache$1.inflightTile[tile.id];
46570                     _cache$1.loadedTile[tile.id] = true;
46571                   }
46572                 });
46573               });
46574               _cache$1.inflightTile[tile.id] = requests;
46575             });
46576           },
46577           getComments: function getComments(item) {
46578             var _this2 = this;
46579
46580             // If comments already retrieved no need to do so again
46581             if (item.comments) {
46582               return Promise.resolve(item);
46583             }
46584
46585             var key = item.issueKey;
46586             var qParams = {};
46587
46588             if (key === 'ow') {
46589               qParams = item.identifier;
46590             } else if (key === 'mr') {
46591               qParams.tileX = item.identifier.x;
46592               qParams.tileY = item.identifier.y;
46593             } else if (key === 'tr') {
46594               qParams.targetId = item.identifier;
46595             }
46596
46597             var url = "".concat(_impOsmUrls[key], "/retrieveComments?") + utilQsString(qParams);
46598
46599             var cacheComments = function cacheComments(data) {
46600               // Assign directly for immediate use afterwards
46601               // comments are served newest to oldest
46602               item.comments = data.comments ? data.comments.reverse() : [];
46603
46604               _this2.replaceItem(item);
46605             };
46606
46607             return d3_json(url).then(cacheComments).then(function () {
46608               return item;
46609             });
46610           },
46611           postUpdate: function postUpdate(d, callback) {
46612             if (!serviceOsm.authenticated()) {
46613               // Username required in payload
46614               return callback({
46615                 message: 'Not Authenticated',
46616                 status: -3
46617               }, d);
46618             }
46619
46620             if (_cache$1.inflightPost[d.id]) {
46621               return callback({
46622                 message: 'Error update already inflight',
46623                 status: -2
46624               }, d);
46625             } // Payload can only be sent once username is established
46626
46627
46628             serviceOsm.userDetails(sendPayload.bind(this));
46629
46630             function sendPayload(err, user) {
46631               var _this3 = this;
46632
46633               if (err) {
46634                 return callback(err, d);
46635               }
46636
46637               var key = d.issueKey;
46638               var url = "".concat(_impOsmUrls[key], "/comment");
46639               var payload = {
46640                 username: user.display_name,
46641                 targetIds: [d.identifier]
46642               };
46643
46644               if (d.newStatus) {
46645                 payload.status = d.newStatus;
46646                 payload.text = 'status changed';
46647               } // Comment take place of default text
46648
46649
46650               if (d.newComment) {
46651                 payload.text = d.newComment;
46652               }
46653
46654               var controller = new AbortController();
46655               _cache$1.inflightPost[d.id] = controller;
46656               var options = {
46657                 method: 'POST',
46658                 signal: controller.signal,
46659                 body: JSON.stringify(payload)
46660               };
46661               d3_json(url, options).then(function () {
46662                 delete _cache$1.inflightPost[d.id]; // Just a comment, update error in cache
46663
46664                 if (!d.newStatus) {
46665                   var now = new Date();
46666                   var comments = d.comments ? d.comments : [];
46667                   comments.push({
46668                     username: payload.username,
46669                     text: payload.text,
46670                     timestamp: now.getTime() / 1000
46671                   });
46672
46673                   _this3.replaceItem(d.update({
46674                     comments: comments,
46675                     newComment: undefined
46676                   }));
46677                 } else {
46678                   _this3.removeItem(d);
46679
46680                   if (d.newStatus === 'SOLVED') {
46681                     // Keep track of the number of issues closed per type to tag the changeset
46682                     if (!(d.issueKey in _cache$1.closed)) {
46683                       _cache$1.closed[d.issueKey] = 0;
46684                     }
46685
46686                     _cache$1.closed[d.issueKey] += 1;
46687                   }
46688                 }
46689
46690                 if (callback) callback(null, d);
46691               })["catch"](function (err) {
46692                 delete _cache$1.inflightPost[d.id];
46693                 if (callback) callback(err.message);
46694               });
46695             }
46696           },
46697           // Get all cached QAItems covering the viewport
46698           getItems: function getItems(projection) {
46699             var viewport = projection.clipExtent();
46700             var min = [viewport[0][0], viewport[1][1]];
46701             var max = [viewport[1][0], viewport[0][1]];
46702             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
46703             return _cache$1.rtree.search(bbox).map(function (d) {
46704               return d.data;
46705             });
46706           },
46707           // Get a QAItem from cache
46708           // NOTE: Don't change method name until UI v3 is merged
46709           getError: function getError(id) {
46710             return _cache$1.data[id];
46711           },
46712           // get the name of the icon to display for this item
46713           getIcon: function getIcon(itemType) {
46714             return _impOsmData.icons[itemType];
46715           },
46716           // Replace a single QAItem in the cache
46717           replaceItem: function replaceItem(issue) {
46718             if (!(issue instanceof QAItem) || !issue.id) return;
46719             _cache$1.data[issue.id] = issue;
46720             updateRtree$2(encodeIssueRtree$1(issue), true); // true = replace
46721
46722             return issue;
46723           },
46724           // Remove a single QAItem from the cache
46725           removeItem: function removeItem(issue) {
46726             if (!(issue instanceof QAItem) || !issue.id) return;
46727             delete _cache$1.data[issue.id];
46728             updateRtree$2(encodeIssueRtree$1(issue), false); // false = remove
46729           },
46730           // Used to populate `closed:improveosm:*` changeset tags
46731           getClosedCounts: function getClosedCounts() {
46732             return _cache$1.closed;
46733           }
46734         };
46735
46736         var defaults$5 = createCommonjsModule(function (module) {
46737           function getDefaults() {
46738             return {
46739               baseUrl: null,
46740               breaks: false,
46741               gfm: true,
46742               headerIds: true,
46743               headerPrefix: '',
46744               highlight: null,
46745               langPrefix: 'language-',
46746               mangle: true,
46747               pedantic: false,
46748               renderer: null,
46749               sanitize: false,
46750               sanitizer: null,
46751               silent: false,
46752               smartLists: false,
46753               smartypants: false,
46754               tokenizer: null,
46755               walkTokens: null,
46756               xhtml: false
46757             };
46758           }
46759
46760           function changeDefaults(newDefaults) {
46761             module.exports.defaults = newDefaults;
46762           }
46763
46764           module.exports = {
46765             defaults: getDefaults(),
46766             getDefaults: getDefaults,
46767             changeDefaults: changeDefaults
46768           };
46769         });
46770
46771         /**
46772          * Helpers
46773          */
46774         var escapeTest = /[&<>"']/;
46775         var escapeReplace = /[&<>"']/g;
46776         var escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
46777         var escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
46778         var escapeReplacements = {
46779           '&': '&amp;',
46780           '<': '&lt;',
46781           '>': '&gt;',
46782           '"': '&quot;',
46783           "'": '&#39;'
46784         };
46785
46786         var getEscapeReplacement = function getEscapeReplacement(ch) {
46787           return escapeReplacements[ch];
46788         };
46789
46790         function escape$3(html, encode) {
46791           if (encode) {
46792             if (escapeTest.test(html)) {
46793               return html.replace(escapeReplace, getEscapeReplacement);
46794             }
46795           } else {
46796             if (escapeTestNoEncode.test(html)) {
46797               return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
46798             }
46799           }
46800
46801           return html;
46802         }
46803
46804         var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
46805
46806         function unescape$2(html) {
46807           // explicitly match decimal, hex, and named HTML entities
46808           return html.replace(unescapeTest, function (_, n) {
46809             n = n.toLowerCase();
46810             if (n === 'colon') return ':';
46811
46812             if (n.charAt(0) === '#') {
46813               return n.charAt(1) === 'x' ? String.fromCharCode(parseInt(n.substring(2), 16)) : String.fromCharCode(+n.substring(1));
46814             }
46815
46816             return '';
46817           });
46818         }
46819
46820         var caret = /(^|[^\[])\^/g;
46821
46822         function edit$1(regex, opt) {
46823           regex = regex.source || regex;
46824           opt = opt || '';
46825           var obj = {
46826             replace: function replace(name, val) {
46827               val = val.source || val;
46828               val = val.replace(caret, '$1');
46829               regex = regex.replace(name, val);
46830               return obj;
46831             },
46832             getRegex: function getRegex() {
46833               return new RegExp(regex, opt);
46834             }
46835           };
46836           return obj;
46837         }
46838
46839         var nonWordAndColonTest = /[^\w:]/g;
46840         var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
46841
46842         function cleanUrl$1(sanitize, base, href) {
46843           if (sanitize) {
46844             var prot;
46845
46846             try {
46847               prot = decodeURIComponent(unescape$2(href)).replace(nonWordAndColonTest, '').toLowerCase();
46848             } catch (e) {
46849               return null;
46850             }
46851
46852             if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
46853               return null;
46854             }
46855           }
46856
46857           if (base && !originIndependentUrl.test(href)) {
46858             href = resolveUrl$1(base, href);
46859           }
46860
46861           try {
46862             href = encodeURI(href).replace(/%25/g, '%');
46863           } catch (e) {
46864             return null;
46865           }
46866
46867           return href;
46868         }
46869
46870         var baseUrls = {};
46871         var justDomain = /^[^:]+:\/*[^/]*$/;
46872         var protocol = /^([^:]+:)[\s\S]*$/;
46873         var domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
46874
46875         function resolveUrl$1(base, href) {
46876           if (!baseUrls[' ' + base]) {
46877             // we can ignore everything in base after the last slash of its path component,
46878             // but we might need to add _that_
46879             // https://tools.ietf.org/html/rfc3986#section-3
46880             if (justDomain.test(base)) {
46881               baseUrls[' ' + base] = base + '/';
46882             } else {
46883               baseUrls[' ' + base] = rtrim$1(base, '/', true);
46884             }
46885           }
46886
46887           base = baseUrls[' ' + base];
46888           var relativeBase = base.indexOf(':') === -1;
46889
46890           if (href.substring(0, 2) === '//') {
46891             if (relativeBase) {
46892               return href;
46893             }
46894
46895             return base.replace(protocol, '$1') + href;
46896           } else if (href.charAt(0) === '/') {
46897             if (relativeBase) {
46898               return href;
46899             }
46900
46901             return base.replace(domain, '$1') + href;
46902           } else {
46903             return base + href;
46904           }
46905         }
46906
46907         var noopTest$1 = {
46908           exec: function noopTest() {}
46909         };
46910
46911         function merge$2(obj) {
46912           var i = 1,
46913               target,
46914               key;
46915
46916           for (; i < arguments.length; i++) {
46917             target = arguments[i];
46918
46919             for (key in target) {
46920               if (Object.prototype.hasOwnProperty.call(target, key)) {
46921                 obj[key] = target[key];
46922               }
46923             }
46924           }
46925
46926           return obj;
46927         }
46928
46929         function splitCells$1(tableRow, count) {
46930           // ensure that every cell-delimiting pipe has a space
46931           // before it to distinguish it from an escaped pipe
46932           var row = tableRow.replace(/\|/g, function (match, offset, str) {
46933             var escaped = false,
46934                 curr = offset;
46935
46936             while (--curr >= 0 && str[curr] === '\\') {
46937               escaped = !escaped;
46938             }
46939
46940             if (escaped) {
46941               // odd number of slashes means | is escaped
46942               // so we leave it alone
46943               return '|';
46944             } else {
46945               // add space before unescaped |
46946               return ' |';
46947             }
46948           }),
46949               cells = row.split(/ \|/);
46950           var i = 0;
46951
46952           if (cells.length > count) {
46953             cells.splice(count);
46954           } else {
46955             while (cells.length < count) {
46956               cells.push('');
46957             }
46958           }
46959
46960           for (; i < cells.length; i++) {
46961             // leading or trailing whitespace is ignored per the gfm spec
46962             cells[i] = cells[i].trim().replace(/\\\|/g, '|');
46963           }
46964
46965           return cells;
46966         } // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
46967         // /c*$/ is vulnerable to REDOS.
46968         // invert: Remove suffix of non-c chars instead. Default falsey.
46969
46970
46971         function rtrim$1(str, c, invert) {
46972           var l = str.length;
46973
46974           if (l === 0) {
46975             return '';
46976           } // Length of suffix matching the invert condition.
46977
46978
46979           var suffLen = 0; // Step left until we fail to match the invert condition.
46980
46981           while (suffLen < l) {
46982             var currChar = str.charAt(l - suffLen - 1);
46983
46984             if (currChar === c && !invert) {
46985               suffLen++;
46986             } else if (currChar !== c && invert) {
46987               suffLen++;
46988             } else {
46989               break;
46990             }
46991           }
46992
46993           return str.substr(0, l - suffLen);
46994         }
46995
46996         function findClosingBracket$1(str, b) {
46997           if (str.indexOf(b[1]) === -1) {
46998             return -1;
46999           }
47000
47001           var l = str.length;
47002           var level = 0,
47003               i = 0;
47004
47005           for (; i < l; i++) {
47006             if (str[i] === '\\') {
47007               i++;
47008             } else if (str[i] === b[0]) {
47009               level++;
47010             } else if (str[i] === b[1]) {
47011               level--;
47012
47013               if (level < 0) {
47014                 return i;
47015               }
47016             }
47017           }
47018
47019           return -1;
47020         }
47021
47022         function checkSanitizeDeprecation$1(opt) {
47023           if (opt && opt.sanitize && !opt.silent) {
47024             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');
47025           }
47026         } // copied from https://stackoverflow.com/a/5450113/806777
47027
47028
47029         function repeatString$1(pattern, count) {
47030           if (count < 1) {
47031             return '';
47032           }
47033
47034           var result = '';
47035
47036           while (count > 1) {
47037             if (count & 1) {
47038               result += pattern;
47039             }
47040
47041             count >>= 1;
47042             pattern += pattern;
47043           }
47044
47045           return result + pattern;
47046         }
47047
47048         var helpers = {
47049           escape: escape$3,
47050           unescape: unescape$2,
47051           edit: edit$1,
47052           cleanUrl: cleanUrl$1,
47053           resolveUrl: resolveUrl$1,
47054           noopTest: noopTest$1,
47055           merge: merge$2,
47056           splitCells: splitCells$1,
47057           rtrim: rtrim$1,
47058           findClosingBracket: findClosingBracket$1,
47059           checkSanitizeDeprecation: checkSanitizeDeprecation$1,
47060           repeatString: repeatString$1
47061         };
47062
47063         var defaults$4 = defaults$5.defaults;
47064         var rtrim = helpers.rtrim,
47065             splitCells = helpers.splitCells,
47066             _escape = helpers.escape,
47067             findClosingBracket = helpers.findClosingBracket;
47068
47069         function outputLink(cap, link, raw) {
47070           var href = link.href;
47071           var title = link.title ? _escape(link.title) : null;
47072           var text = cap[1].replace(/\\([\[\]])/g, '$1');
47073
47074           if (cap[0].charAt(0) !== '!') {
47075             return {
47076               type: 'link',
47077               raw: raw,
47078               href: href,
47079               title: title,
47080               text: text
47081             };
47082           } else {
47083             return {
47084               type: 'image',
47085               raw: raw,
47086               href: href,
47087               title: title,
47088               text: _escape(text)
47089             };
47090           }
47091         }
47092
47093         function indentCodeCompensation(raw, text) {
47094           var matchIndentToCode = raw.match(/^(\s+)(?:```)/);
47095
47096           if (matchIndentToCode === null) {
47097             return text;
47098           }
47099
47100           var indentToCode = matchIndentToCode[1];
47101           return text.split('\n').map(function (node) {
47102             var matchIndentInNode = node.match(/^\s+/);
47103
47104             if (matchIndentInNode === null) {
47105               return node;
47106             }
47107
47108             var _matchIndentInNode = _slicedToArray(matchIndentInNode, 1),
47109                 indentInNode = _matchIndentInNode[0];
47110
47111             if (indentInNode.length >= indentToCode.length) {
47112               return node.slice(indentToCode.length);
47113             }
47114
47115             return node;
47116           }).join('\n');
47117         }
47118         /**
47119          * Tokenizer
47120          */
47121
47122
47123         var Tokenizer_1 = /*#__PURE__*/function () {
47124           function Tokenizer(options) {
47125             _classCallCheck$1(this, Tokenizer);
47126
47127             this.options = options || defaults$4;
47128           }
47129
47130           _createClass$1(Tokenizer, [{
47131             key: "space",
47132             value: function space(src) {
47133               var cap = this.rules.block.newline.exec(src);
47134
47135               if (cap) {
47136                 if (cap[0].length > 1) {
47137                   return {
47138                     type: 'space',
47139                     raw: cap[0]
47140                   };
47141                 }
47142
47143                 return {
47144                   raw: '\n'
47145                 };
47146               }
47147             }
47148           }, {
47149             key: "code",
47150             value: function code(src) {
47151               var cap = this.rules.block.code.exec(src);
47152
47153               if (cap) {
47154                 var text = cap[0].replace(/^ {1,4}/gm, '');
47155                 return {
47156                   type: 'code',
47157                   raw: cap[0],
47158                   codeBlockStyle: 'indented',
47159                   text: !this.options.pedantic ? rtrim(text, '\n') : text
47160                 };
47161               }
47162             }
47163           }, {
47164             key: "fences",
47165             value: function fences(src) {
47166               var cap = this.rules.block.fences.exec(src);
47167
47168               if (cap) {
47169                 var raw = cap[0];
47170                 var text = indentCodeCompensation(raw, cap[3] || '');
47171                 return {
47172                   type: 'code',
47173                   raw: raw,
47174                   lang: cap[2] ? cap[2].trim() : cap[2],
47175                   text: text
47176                 };
47177               }
47178             }
47179           }, {
47180             key: "heading",
47181             value: function heading(src) {
47182               var cap = this.rules.block.heading.exec(src);
47183
47184               if (cap) {
47185                 var text = cap[2].trim(); // remove trailing #s
47186
47187                 if (/#$/.test(text)) {
47188                   var trimmed = rtrim(text, '#');
47189
47190                   if (this.options.pedantic) {
47191                     text = trimmed.trim();
47192                   } else if (!trimmed || / $/.test(trimmed)) {
47193                     // CommonMark requires space before trailing #s
47194                     text = trimmed.trim();
47195                   }
47196                 }
47197
47198                 return {
47199                   type: 'heading',
47200                   raw: cap[0],
47201                   depth: cap[1].length,
47202                   text: text
47203                 };
47204               }
47205             }
47206           }, {
47207             key: "nptable",
47208             value: function nptable(src) {
47209               var cap = this.rules.block.nptable.exec(src);
47210
47211               if (cap) {
47212                 var item = {
47213                   type: 'table',
47214                   header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
47215                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
47216                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [],
47217                   raw: cap[0]
47218                 };
47219
47220                 if (item.header.length === item.align.length) {
47221                   var l = item.align.length;
47222                   var i;
47223
47224                   for (i = 0; i < l; i++) {
47225                     if (/^ *-+: *$/.test(item.align[i])) {
47226                       item.align[i] = 'right';
47227                     } else if (/^ *:-+: *$/.test(item.align[i])) {
47228                       item.align[i] = 'center';
47229                     } else if (/^ *:-+ *$/.test(item.align[i])) {
47230                       item.align[i] = 'left';
47231                     } else {
47232                       item.align[i] = null;
47233                     }
47234                   }
47235
47236                   l = item.cells.length;
47237
47238                   for (i = 0; i < l; i++) {
47239                     item.cells[i] = splitCells(item.cells[i], item.header.length);
47240                   }
47241
47242                   return item;
47243                 }
47244               }
47245             }
47246           }, {
47247             key: "hr",
47248             value: function hr(src) {
47249               var cap = this.rules.block.hr.exec(src);
47250
47251               if (cap) {
47252                 return {
47253                   type: 'hr',
47254                   raw: cap[0]
47255                 };
47256               }
47257             }
47258           }, {
47259             key: "blockquote",
47260             value: function blockquote(src) {
47261               var cap = this.rules.block.blockquote.exec(src);
47262
47263               if (cap) {
47264                 var text = cap[0].replace(/^ *> ?/gm, '');
47265                 return {
47266                   type: 'blockquote',
47267                   raw: cap[0],
47268                   text: text
47269                 };
47270               }
47271             }
47272           }, {
47273             key: "list",
47274             value: function list(src) {
47275               var cap = this.rules.block.list.exec(src);
47276
47277               if (cap) {
47278                 var raw = cap[0];
47279                 var bull = cap[2];
47280                 var isordered = bull.length > 1;
47281                 var list = {
47282                   type: 'list',
47283                   raw: raw,
47284                   ordered: isordered,
47285                   start: isordered ? +bull.slice(0, -1) : '',
47286                   loose: false,
47287                   items: []
47288                 }; // Get each top-level item.
47289
47290                 var itemMatch = cap[0].match(this.rules.block.item);
47291                 var next = false,
47292                     item,
47293                     space,
47294                     bcurr,
47295                     bnext,
47296                     addBack,
47297                     loose,
47298                     istask,
47299                     ischecked,
47300                     endMatch;
47301                 var l = itemMatch.length;
47302                 bcurr = this.rules.block.listItemStart.exec(itemMatch[0]);
47303
47304                 for (var i = 0; i < l; i++) {
47305                   item = itemMatch[i];
47306                   raw = item;
47307
47308                   if (!this.options.pedantic) {
47309                     // Determine if current item contains the end of the list
47310                     endMatch = item.match(new RegExp('\\n\\s*\\n {0,' + (bcurr[0].length - 1) + '}\\S'));
47311
47312                     if (endMatch) {
47313                       addBack = item.length - endMatch.index + itemMatch.slice(i + 1).join('\n').length;
47314                       list.raw = list.raw.substring(0, list.raw.length - addBack);
47315                       item = item.substring(0, endMatch.index);
47316                       raw = item;
47317                       l = i + 1;
47318                     }
47319                   } // Determine whether the next list item belongs here.
47320                   // Backpedal if it does not belong in this list.
47321
47322
47323                   if (i !== l - 1) {
47324                     bnext = this.rules.block.listItemStart.exec(itemMatch[i + 1]);
47325
47326                     if (!this.options.pedantic ? bnext[1].length >= bcurr[0].length || bnext[1].length > 3 : bnext[1].length > bcurr[1].length) {
47327                       // nested list or continuation
47328                       itemMatch.splice(i, 2, itemMatch[i] + (!this.options.pedantic && bnext[1].length < bcurr[0].length && !itemMatch[i].match(/\n$/) ? '' : '\n') + itemMatch[i + 1]);
47329                       i--;
47330                       l--;
47331                       continue;
47332                     } else if ( // different bullet style
47333                     !this.options.pedantic || this.options.smartLists ? bnext[2][bnext[2].length - 1] !== bull[bull.length - 1] : isordered === (bnext[2].length === 1)) {
47334                       addBack = itemMatch.slice(i + 1).join('\n').length;
47335                       list.raw = list.raw.substring(0, list.raw.length - addBack);
47336                       i = l - 1;
47337                     }
47338
47339                     bcurr = bnext;
47340                   } // Remove the list item's bullet
47341                   // so it is seen as the next token.
47342
47343
47344                   space = item.length;
47345                   item = item.replace(/^ *([*+-]|\d+[.)]) ?/, ''); // Outdent whatever the
47346                   // list item contains. Hacky.
47347
47348                   if (~item.indexOf('\n ')) {
47349                     space -= item.length;
47350                     item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, '');
47351                   } // trim item newlines at end
47352
47353
47354                   item = rtrim(item, '\n');
47355
47356                   if (i !== l - 1) {
47357                     raw = raw + '\n';
47358                   } // Determine whether item is loose or not.
47359                   // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
47360                   // for discount behavior.
47361
47362
47363                   loose = next || /\n\n(?!\s*$)/.test(raw);
47364
47365                   if (i !== l - 1) {
47366                     next = raw.slice(-2) === '\n\n';
47367                     if (!loose) loose = next;
47368                   }
47369
47370                   if (loose) {
47371                     list.loose = true;
47372                   } // Check for task list items
47373
47374
47375                   if (this.options.gfm) {
47376                     istask = /^\[[ xX]\] /.test(item);
47377                     ischecked = undefined;
47378
47379                     if (istask) {
47380                       ischecked = item[1] !== ' ';
47381                       item = item.replace(/^\[[ xX]\] +/, '');
47382                     }
47383                   }
47384
47385                   list.items.push({
47386                     type: 'list_item',
47387                     raw: raw,
47388                     task: istask,
47389                     checked: ischecked,
47390                     loose: loose,
47391                     text: item
47392                   });
47393                 }
47394
47395                 return list;
47396               }
47397             }
47398           }, {
47399             key: "html",
47400             value: function html(src) {
47401               var cap = this.rules.block.html.exec(src);
47402
47403               if (cap) {
47404                 return {
47405                   type: this.options.sanitize ? 'paragraph' : 'html',
47406                   raw: cap[0],
47407                   pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
47408                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
47409                 };
47410               }
47411             }
47412           }, {
47413             key: "def",
47414             value: function def(src) {
47415               var cap = this.rules.block.def.exec(src);
47416
47417               if (cap) {
47418                 if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
47419                 var tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
47420                 return {
47421                   type: 'def',
47422                   tag: tag,
47423                   raw: cap[0],
47424                   href: cap[2],
47425                   title: cap[3]
47426                 };
47427               }
47428             }
47429           }, {
47430             key: "table",
47431             value: function table(src) {
47432               var cap = this.rules.block.table.exec(src);
47433
47434               if (cap) {
47435                 var item = {
47436                   type: 'table',
47437                   header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
47438                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
47439                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
47440                 };
47441
47442                 if (item.header.length === item.align.length) {
47443                   item.raw = cap[0];
47444                   var l = item.align.length;
47445                   var i;
47446
47447                   for (i = 0; i < l; i++) {
47448                     if (/^ *-+: *$/.test(item.align[i])) {
47449                       item.align[i] = 'right';
47450                     } else if (/^ *:-+: *$/.test(item.align[i])) {
47451                       item.align[i] = 'center';
47452                     } else if (/^ *:-+ *$/.test(item.align[i])) {
47453                       item.align[i] = 'left';
47454                     } else {
47455                       item.align[i] = null;
47456                     }
47457                   }
47458
47459                   l = item.cells.length;
47460
47461                   for (i = 0; i < l; i++) {
47462                     item.cells[i] = splitCells(item.cells[i].replace(/^ *\| *| *\| *$/g, ''), item.header.length);
47463                   }
47464
47465                   return item;
47466                 }
47467               }
47468             }
47469           }, {
47470             key: "lheading",
47471             value: function lheading(src) {
47472               var cap = this.rules.block.lheading.exec(src);
47473
47474               if (cap) {
47475                 return {
47476                   type: 'heading',
47477                   raw: cap[0],
47478                   depth: cap[2].charAt(0) === '=' ? 1 : 2,
47479                   text: cap[1]
47480                 };
47481               }
47482             }
47483           }, {
47484             key: "paragraph",
47485             value: function paragraph(src) {
47486               var cap = this.rules.block.paragraph.exec(src);
47487
47488               if (cap) {
47489                 return {
47490                   type: 'paragraph',
47491                   raw: cap[0],
47492                   text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]
47493                 };
47494               }
47495             }
47496           }, {
47497             key: "text",
47498             value: function text(src) {
47499               var cap = this.rules.block.text.exec(src);
47500
47501               if (cap) {
47502                 return {
47503                   type: 'text',
47504                   raw: cap[0],
47505                   text: cap[0]
47506                 };
47507               }
47508             }
47509           }, {
47510             key: "escape",
47511             value: function escape(src) {
47512               var cap = this.rules.inline.escape.exec(src);
47513
47514               if (cap) {
47515                 return {
47516                   type: 'escape',
47517                   raw: cap[0],
47518                   text: _escape(cap[1])
47519                 };
47520               }
47521             }
47522           }, {
47523             key: "tag",
47524             value: function tag(src, inLink, inRawBlock) {
47525               var cap = this.rules.inline.tag.exec(src);
47526
47527               if (cap) {
47528                 if (!inLink && /^<a /i.test(cap[0])) {
47529                   inLink = true;
47530                 } else if (inLink && /^<\/a>/i.test(cap[0])) {
47531                   inLink = false;
47532                 }
47533
47534                 if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
47535                   inRawBlock = true;
47536                 } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
47537                   inRawBlock = false;
47538                 }
47539
47540                 return {
47541                   type: this.options.sanitize ? 'text' : 'html',
47542                   raw: cap[0],
47543                   inLink: inLink,
47544                   inRawBlock: inRawBlock,
47545                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
47546                 };
47547               }
47548             }
47549           }, {
47550             key: "link",
47551             value: function link(src) {
47552               var cap = this.rules.inline.link.exec(src);
47553
47554               if (cap) {
47555                 var trimmedUrl = cap[2].trim();
47556
47557                 if (!this.options.pedantic && /^</.test(trimmedUrl)) {
47558                   // commonmark requires matching angle brackets
47559                   if (!/>$/.test(trimmedUrl)) {
47560                     return;
47561                   } // ending angle bracket cannot be escaped
47562
47563
47564                   var rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
47565
47566                   if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
47567                     return;
47568                   }
47569                 } else {
47570                   // find closing parenthesis
47571                   var lastParenIndex = findClosingBracket(cap[2], '()');
47572
47573                   if (lastParenIndex > -1) {
47574                     var start = cap[0].indexOf('!') === 0 ? 5 : 4;
47575                     var linkLen = start + cap[1].length + lastParenIndex;
47576                     cap[2] = cap[2].substring(0, lastParenIndex);
47577                     cap[0] = cap[0].substring(0, linkLen).trim();
47578                     cap[3] = '';
47579                   }
47580                 }
47581
47582                 var href = cap[2];
47583                 var title = '';
47584
47585                 if (this.options.pedantic) {
47586                   // split pedantic href and title
47587                   var link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
47588
47589                   if (link) {
47590                     href = link[1];
47591                     title = link[3];
47592                   }
47593                 } else {
47594                   title = cap[3] ? cap[3].slice(1, -1) : '';
47595                 }
47596
47597                 href = href.trim();
47598
47599                 if (/^</.test(href)) {
47600                   if (this.options.pedantic && !/>$/.test(trimmedUrl)) {
47601                     // pedantic allows starting angle bracket without ending angle bracket
47602                     href = href.slice(1);
47603                   } else {
47604                     href = href.slice(1, -1);
47605                   }
47606                 }
47607
47608                 return outputLink(cap, {
47609                   href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
47610                   title: title ? title.replace(this.rules.inline._escapes, '$1') : title
47611                 }, cap[0]);
47612               }
47613             }
47614           }, {
47615             key: "reflink",
47616             value: function reflink(src, links) {
47617               var cap;
47618
47619               if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
47620                 var link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
47621                 link = links[link.toLowerCase()];
47622
47623                 if (!link || !link.href) {
47624                   var text = cap[0].charAt(0);
47625                   return {
47626                     type: 'text',
47627                     raw: text,
47628                     text: text
47629                   };
47630                 }
47631
47632                 return outputLink(cap, link, cap[0]);
47633               }
47634             }
47635           }, {
47636             key: "emStrong",
47637             value: function emStrong(src, maskedSrc) {
47638               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
47639               var match = this.rules.inline.emStrong.lDelim.exec(src);
47640               if (!match) return; // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
47641
47642               if (match[3] && prevChar.match(/(?:[0-9A-Za-z\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BF\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54\uDFB0-\uDFCB\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEB8\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDD50-\uDD59\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2\uDFB0\uDFC0-\uDFD4]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD40-\uDD49\uDD4E\uDEC0-\uDEEB\uDEF0-\uDEF9]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD4B\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])/)) return;
47643               var nextChar = match[1] || match[2] || '';
47644
47645               if (!nextChar || nextChar && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar))) {
47646                 var lLength = match[0].length - 1;
47647                 var rDelim,
47648                     rLength,
47649                     delimTotal = lLength,
47650                     midDelimTotal = 0;
47651                 var endReg = match[0][0] === '*' ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
47652                 endReg.lastIndex = 0; // Clip maskedSrc to same section of string as src (move to lexer?)
47653
47654                 maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
47655
47656                 while ((match = endReg.exec(maskedSrc)) != null) {
47657                   rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
47658                   if (!rDelim) continue; // skip single * in __abc*abc__
47659
47660                   rLength = rDelim.length;
47661
47662                   if (match[3] || match[4]) {
47663                     // found another Left Delim
47664                     delimTotal += rLength;
47665                     continue;
47666                   } else if (match[5] || match[6]) {
47667                     // either Left or Right Delim
47668                     if (lLength % 3 && !((lLength + rLength) % 3)) {
47669                       midDelimTotal += rLength;
47670                       continue; // CommonMark Emphasis Rules 9-10
47671                     }
47672                   }
47673
47674                   delimTotal -= rLength;
47675                   if (delimTotal > 0) continue; // Haven't found enough closing delimiters
47676                   // Remove extra characters. *a*** -> *a*
47677
47678                   rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal); // Create `em` if smallest delimiter has odd char count. *a***
47679
47680                   if (Math.min(lLength, rLength) % 2) {
47681                     return {
47682                       type: 'em',
47683                       raw: src.slice(0, lLength + match.index + rLength + 1),
47684                       text: src.slice(1, lLength + match.index + rLength)
47685                     };
47686                   } // Create 'strong' if smallest delimiter has even char count. **a***
47687
47688
47689                   return {
47690                     type: 'strong',
47691                     raw: src.slice(0, lLength + match.index + rLength + 1),
47692                     text: src.slice(2, lLength + match.index + rLength - 1)
47693                   };
47694                 }
47695               }
47696             }
47697           }, {
47698             key: "codespan",
47699             value: function codespan(src) {
47700               var cap = this.rules.inline.code.exec(src);
47701
47702               if (cap) {
47703                 var text = cap[2].replace(/\n/g, ' ');
47704                 var hasNonSpaceChars = /[^ ]/.test(text);
47705                 var hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
47706
47707                 if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
47708                   text = text.substring(1, text.length - 1);
47709                 }
47710
47711                 text = _escape(text, true);
47712                 return {
47713                   type: 'codespan',
47714                   raw: cap[0],
47715                   text: text
47716                 };
47717               }
47718             }
47719           }, {
47720             key: "br",
47721             value: function br(src) {
47722               var cap = this.rules.inline.br.exec(src);
47723
47724               if (cap) {
47725                 return {
47726                   type: 'br',
47727                   raw: cap[0]
47728                 };
47729               }
47730             }
47731           }, {
47732             key: "del",
47733             value: function del(src) {
47734               var cap = this.rules.inline.del.exec(src);
47735
47736               if (cap) {
47737                 return {
47738                   type: 'del',
47739                   raw: cap[0],
47740                   text: cap[2]
47741                 };
47742               }
47743             }
47744           }, {
47745             key: "autolink",
47746             value: function autolink(src, mangle) {
47747               var cap = this.rules.inline.autolink.exec(src);
47748
47749               if (cap) {
47750                 var text, href;
47751
47752                 if (cap[2] === '@') {
47753                   text = _escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
47754                   href = 'mailto:' + text;
47755                 } else {
47756                   text = _escape(cap[1]);
47757                   href = text;
47758                 }
47759
47760                 return {
47761                   type: 'link',
47762                   raw: cap[0],
47763                   text: text,
47764                   href: href,
47765                   tokens: [{
47766                     type: 'text',
47767                     raw: text,
47768                     text: text
47769                   }]
47770                 };
47771               }
47772             }
47773           }, {
47774             key: "url",
47775             value: function url(src, mangle) {
47776               var cap;
47777
47778               if (cap = this.rules.inline.url.exec(src)) {
47779                 var text, href;
47780
47781                 if (cap[2] === '@') {
47782                   text = _escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
47783                   href = 'mailto:' + text;
47784                 } else {
47785                   // do extended autolink path validation
47786                   var prevCapZero;
47787
47788                   do {
47789                     prevCapZero = cap[0];
47790                     cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
47791                   } while (prevCapZero !== cap[0]);
47792
47793                   text = _escape(cap[0]);
47794
47795                   if (cap[1] === 'www.') {
47796                     href = 'http://' + text;
47797                   } else {
47798                     href = text;
47799                   }
47800                 }
47801
47802                 return {
47803                   type: 'link',
47804                   raw: cap[0],
47805                   text: text,
47806                   href: href,
47807                   tokens: [{
47808                     type: 'text',
47809                     raw: text,
47810                     text: text
47811                   }]
47812                 };
47813               }
47814             }
47815           }, {
47816             key: "inlineText",
47817             value: function inlineText(src, inRawBlock, smartypants) {
47818               var cap = this.rules.inline.text.exec(src);
47819
47820               if (cap) {
47821                 var text;
47822
47823                 if (inRawBlock) {
47824                   text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0];
47825                 } else {
47826                   text = _escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
47827                 }
47828
47829                 return {
47830                   type: 'text',
47831                   raw: cap[0],
47832                   text: text
47833                 };
47834               }
47835             }
47836           }]);
47837
47838           return Tokenizer;
47839         }();
47840
47841         var noopTest = helpers.noopTest,
47842             edit = helpers.edit,
47843             merge$1 = helpers.merge;
47844         /**
47845          * Block-Level Grammar
47846          */
47847
47848         var block$1 = {
47849           newline: /^(?: *(?:\n|$))+/,
47850           code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
47851           fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
47852           hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
47853           heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
47854           blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
47855           list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,
47856           html: '^ {0,3}(?:' // optional indentation
47857           + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
47858           + '|comment[^\\n]*(\\n+|$)' // (2)
47859           + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
47860           + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
47861           + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
47862           + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6)
47863           + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
47864           + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
47865           + ')',
47866           def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
47867           nptable: noopTest,
47868           table: noopTest,
47869           lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
47870           // regex template, placeholders will be replaced according to different paragraph
47871           // interruption rules of commonmark and the original markdown spec:
47872           _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,
47873           text: /^[^\n]+/
47874         };
47875         block$1._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
47876         block$1._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
47877         block$1.def = edit(block$1.def).replace('label', block$1._label).replace('title', block$1._title).getRegex();
47878         block$1.bullet = /(?:[*+-]|\d{1,9}[.)])/;
47879         block$1.item = /^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/;
47880         block$1.item = edit(block$1.item, 'gm').replace(/bull/g, block$1.bullet).getRegex();
47881         block$1.listItemStart = edit(/^( *)(bull) */).replace('bull', block$1.bullet).getRegex();
47882         block$1.list = edit(block$1.list).replace(/bull/g, block$1.bullet).replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))').replace('def', '\\n+(?=' + block$1.def.source + ')').getRegex();
47883         block$1._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';
47884         block$1._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
47885         block$1.html = edit(block$1.html, 'i').replace('comment', block$1._comment).replace('tag', block$1._tag).replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
47886         block$1.paragraph = edit(block$1._paragraph).replace('hr', block$1.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
47887         .replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
47888         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block$1._tag) // pars can be interrupted by type (6) html blocks
47889         .getRegex();
47890         block$1.blockquote = edit(block$1.blockquote).replace('paragraph', block$1.paragraph).getRegex();
47891         /**
47892          * Normal Block Grammar
47893          */
47894
47895         block$1.normal = merge$1({}, block$1);
47896         /**
47897          * GFM Block Grammar
47898          */
47899
47900         block$1.gfm = merge$1({}, block$1.normal, {
47901           nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header
47902           + ' {0,3}([-:]+ *\\|[-| :]*)' // Align
47903           + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)',
47904           // Cells
47905           table: '^ *\\|(.+)\\n' // Header
47906           + ' {0,3}\\|?( *[-:]+[-| :]*)' // Align
47907           + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
47908
47909         });
47910         block$1.gfm.nptable = edit(block$1.gfm.nptable).replace('hr', block$1.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[.)]) ') // only lists starting from 1 can interrupt
47911         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block$1._tag) // tables can be interrupted by type (6) html blocks
47912         .getRegex();
47913         block$1.gfm.table = edit(block$1.gfm.table).replace('hr', block$1.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[.)]) ') // only lists starting from 1 can interrupt
47914         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block$1._tag) // tables can be interrupted by type (6) html blocks
47915         .getRegex();
47916         /**
47917          * Pedantic grammar (original John Gruber's loose markdown specification)
47918          */
47919
47920         block$1.pedantic = merge$1({}, block$1.normal, {
47921           html: edit('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
47922           + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))').replace('comment', block$1._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(),
47923           def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
47924           heading: /^(#{1,6})(.*)(?:\n+|$)/,
47925           fences: noopTest,
47926           // fences not supported
47927           paragraph: edit(block$1.normal._paragraph).replace('hr', block$1.hr).replace('heading', ' *#{1,6} *[^\n]').replace('lheading', block$1.lheading).replace('blockquote', ' {0,3}>').replace('|fences', '').replace('|list', '').replace('|html', '').getRegex()
47928         });
47929         /**
47930          * Inline-Level Grammar
47931          */
47932
47933         var inline$1 = {
47934           escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
47935           autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
47936           url: noopTest,
47937           tag: '^comment' + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
47938           + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
47939           + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
47940           + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
47941           + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>',
47942           // CDATA section
47943           link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
47944           reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
47945           nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
47946           reflinkSearch: 'reflink|nolink(?!\\()',
47947           emStrong: {
47948             lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
47949             //        (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left.  (5) and (6) can be either Left or Right.
47950             //        () Skip other delimiter (1) #***                   (2) a***#, a***                   (3) #***a, ***a                 (4) ***#              (5) #***#                 (6) a***a
47951             rDelimAst: /\_\_[^_*]*?\*[^_*]*?\_\_|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,
47952             rDelimUnd: /\*\*[^_*]*?\_[^_*]*?\*\*|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/ // ^- Not allowed for _
47953
47954           },
47955           code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
47956           br: /^( {2,}|\\)\n(?!\s*$)/,
47957           del: noopTest,
47958           text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
47959           punctuation: /^([\spunctuation])/
47960         }; // list of punctuation marks from CommonMark spec
47961         // without * and _ to handle the different emphasis markers * and _
47962
47963         inline$1._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
47964         inline$1.punctuation = edit(inline$1.punctuation).replace(/punctuation/g, inline$1._punctuation).getRegex(); // sequences em should skip over [title](link), `code`, <html>
47965
47966         inline$1.blockSkip = /\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g;
47967         inline$1.escapedEmSt = /\\\*|\\_/g;
47968         inline$1._comment = edit(block$1._comment).replace('(?:-->|$)', '-->').getRegex();
47969         inline$1.emStrong.lDelim = edit(inline$1.emStrong.lDelim).replace(/punct/g, inline$1._punctuation).getRegex();
47970         inline$1.emStrong.rDelimAst = edit(inline$1.emStrong.rDelimAst, 'g').replace(/punct/g, inline$1._punctuation).getRegex();
47971         inline$1.emStrong.rDelimUnd = edit(inline$1.emStrong.rDelimUnd, 'g').replace(/punct/g, inline$1._punctuation).getRegex();
47972         inline$1._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
47973         inline$1._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
47974         inline$1._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])?)+(?![-_])/;
47975         inline$1.autolink = edit(inline$1.autolink).replace('scheme', inline$1._scheme).replace('email', inline$1._email).getRegex();
47976         inline$1._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
47977         inline$1.tag = edit(inline$1.tag).replace('comment', inline$1._comment).replace('attribute', inline$1._attribute).getRegex();
47978         inline$1._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
47979         inline$1._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
47980         inline$1._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
47981         inline$1.link = edit(inline$1.link).replace('label', inline$1._label).replace('href', inline$1._href).replace('title', inline$1._title).getRegex();
47982         inline$1.reflink = edit(inline$1.reflink).replace('label', inline$1._label).getRegex();
47983         inline$1.reflinkSearch = edit(inline$1.reflinkSearch, 'g').replace('reflink', inline$1.reflink).replace('nolink', inline$1.nolink).getRegex();
47984         /**
47985          * Normal Inline Grammar
47986          */
47987
47988         inline$1.normal = merge$1({}, inline$1);
47989         /**
47990          * Pedantic Inline Grammar
47991          */
47992
47993         inline$1.pedantic = merge$1({}, inline$1.normal, {
47994           strong: {
47995             start: /^__|\*\*/,
47996             middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
47997             endAst: /\*\*(?!\*)/g,
47998             endUnd: /__(?!_)/g
47999           },
48000           em: {
48001             start: /^_|\*/,
48002             middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
48003             endAst: /\*(?!\*)/g,
48004             endUnd: /_(?!_)/g
48005           },
48006           link: edit(/^!?\[(label)\]\((.*?)\)/).replace('label', inline$1._label).getRegex(),
48007           reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace('label', inline$1._label).getRegex()
48008         });
48009         /**
48010          * GFM Inline Grammar
48011          */
48012
48013         inline$1.gfm = merge$1({}, inline$1.normal, {
48014           escape: edit(inline$1.escape).replace('])', '~|])').getRegex(),
48015           _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
48016           url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
48017           _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
48018           del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
48019           text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
48020         });
48021         inline$1.gfm.url = edit(inline$1.gfm.url, 'i').replace('email', inline$1.gfm._extended_email).getRegex();
48022         /**
48023          * GFM + Line Breaks Inline Grammar
48024          */
48025
48026         inline$1.breaks = merge$1({}, inline$1.gfm, {
48027           br: edit(inline$1.br).replace('{2,}', '*').getRegex(),
48028           text: edit(inline$1.gfm.text).replace('\\b_', '\\b_| {2,}\\n').replace(/\{2,\}/g, '*').getRegex()
48029         });
48030         var rules = {
48031           block: block$1,
48032           inline: inline$1
48033         };
48034
48035         var defaults$3 = defaults$5.defaults;
48036         var block = rules.block,
48037             inline = rules.inline;
48038         var repeatString = helpers.repeatString;
48039         /**
48040          * smartypants text replacement
48041          */
48042
48043         function smartypants(text) {
48044           return text // em-dashes
48045           .replace(/---/g, "\u2014") // en-dashes
48046           .replace(/--/g, "\u2013") // opening singles
48047           .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018") // closing singles & apostrophes
48048           .replace(/'/g, "\u2019") // opening doubles
48049           .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C") // closing doubles
48050           .replace(/"/g, "\u201D") // ellipses
48051           .replace(/\.{3}/g, "\u2026");
48052         }
48053         /**
48054          * mangle email addresses
48055          */
48056
48057
48058         function mangle(text) {
48059           var out = '',
48060               i,
48061               ch;
48062           var l = text.length;
48063
48064           for (i = 0; i < l; i++) {
48065             ch = text.charCodeAt(i);
48066
48067             if (Math.random() > 0.5) {
48068               ch = 'x' + ch.toString(16);
48069             }
48070
48071             out += '&#' + ch + ';';
48072           }
48073
48074           return out;
48075         }
48076         /**
48077          * Block Lexer
48078          */
48079
48080
48081         var Lexer_1 = /*#__PURE__*/function () {
48082           function Lexer(options) {
48083             _classCallCheck$1(this, Lexer);
48084
48085             this.tokens = [];
48086             this.tokens.links = Object.create(null);
48087             this.options = options || defaults$3;
48088             this.options.tokenizer = this.options.tokenizer || new Tokenizer_1();
48089             this.tokenizer = this.options.tokenizer;
48090             this.tokenizer.options = this.options;
48091             var rules = {
48092               block: block.normal,
48093               inline: inline.normal
48094             };
48095
48096             if (this.options.pedantic) {
48097               rules.block = block.pedantic;
48098               rules.inline = inline.pedantic;
48099             } else if (this.options.gfm) {
48100               rules.block = block.gfm;
48101
48102               if (this.options.breaks) {
48103                 rules.inline = inline.breaks;
48104               } else {
48105                 rules.inline = inline.gfm;
48106               }
48107             }
48108
48109             this.tokenizer.rules = rules;
48110           }
48111           /**
48112            * Expose Rules
48113            */
48114
48115
48116           _createClass$1(Lexer, [{
48117             key: "lex",
48118             value:
48119             /**
48120              * Preprocessing
48121              */
48122             function lex(src) {
48123               src = src.replace(/\r\n|\r/g, '\n').replace(/\t/g, '    ');
48124               this.blockTokens(src, this.tokens, true);
48125               this.inline(this.tokens);
48126               return this.tokens;
48127             }
48128             /**
48129              * Lexing
48130              */
48131
48132           }, {
48133             key: "blockTokens",
48134             value: function blockTokens(src) {
48135               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
48136               var top = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
48137
48138               if (this.options.pedantic) {
48139                 src = src.replace(/^ +$/gm, '');
48140               }
48141
48142               var token, i, l, lastToken;
48143
48144               while (src) {
48145                 // newline
48146                 if (token = this.tokenizer.space(src)) {
48147                   src = src.substring(token.raw.length);
48148
48149                   if (token.type) {
48150                     tokens.push(token);
48151                   }
48152
48153                   continue;
48154                 } // code
48155
48156
48157                 if (token = this.tokenizer.code(src)) {
48158                   src = src.substring(token.raw.length);
48159                   lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph.
48160
48161                   if (lastToken && lastToken.type === 'paragraph') {
48162                     lastToken.raw += '\n' + token.raw;
48163                     lastToken.text += '\n' + token.text;
48164                   } else {
48165                     tokens.push(token);
48166                   }
48167
48168                   continue;
48169                 } // fences
48170
48171
48172                 if (token = this.tokenizer.fences(src)) {
48173                   src = src.substring(token.raw.length);
48174                   tokens.push(token);
48175                   continue;
48176                 } // heading
48177
48178
48179                 if (token = this.tokenizer.heading(src)) {
48180                   src = src.substring(token.raw.length);
48181                   tokens.push(token);
48182                   continue;
48183                 } // table no leading pipe (gfm)
48184
48185
48186                 if (token = this.tokenizer.nptable(src)) {
48187                   src = src.substring(token.raw.length);
48188                   tokens.push(token);
48189                   continue;
48190                 } // hr
48191
48192
48193                 if (token = this.tokenizer.hr(src)) {
48194                   src = src.substring(token.raw.length);
48195                   tokens.push(token);
48196                   continue;
48197                 } // blockquote
48198
48199
48200                 if (token = this.tokenizer.blockquote(src)) {
48201                   src = src.substring(token.raw.length);
48202                   token.tokens = this.blockTokens(token.text, [], top);
48203                   tokens.push(token);
48204                   continue;
48205                 } // list
48206
48207
48208                 if (token = this.tokenizer.list(src)) {
48209                   src = src.substring(token.raw.length);
48210                   l = token.items.length;
48211
48212                   for (i = 0; i < l; i++) {
48213                     token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);
48214                   }
48215
48216                   tokens.push(token);
48217                   continue;
48218                 } // html
48219
48220
48221                 if (token = this.tokenizer.html(src)) {
48222                   src = src.substring(token.raw.length);
48223                   tokens.push(token);
48224                   continue;
48225                 } // def
48226
48227
48228                 if (top && (token = this.tokenizer.def(src))) {
48229                   src = src.substring(token.raw.length);
48230
48231                   if (!this.tokens.links[token.tag]) {
48232                     this.tokens.links[token.tag] = {
48233                       href: token.href,
48234                       title: token.title
48235                     };
48236                   }
48237
48238                   continue;
48239                 } // table (gfm)
48240
48241
48242                 if (token = this.tokenizer.table(src)) {
48243                   src = src.substring(token.raw.length);
48244                   tokens.push(token);
48245                   continue;
48246                 } // lheading
48247
48248
48249                 if (token = this.tokenizer.lheading(src)) {
48250                   src = src.substring(token.raw.length);
48251                   tokens.push(token);
48252                   continue;
48253                 } // top-level paragraph
48254
48255
48256                 if (top && (token = this.tokenizer.paragraph(src))) {
48257                   src = src.substring(token.raw.length);
48258                   tokens.push(token);
48259                   continue;
48260                 } // text
48261
48262
48263                 if (token = this.tokenizer.text(src)) {
48264                   src = src.substring(token.raw.length);
48265                   lastToken = tokens[tokens.length - 1];
48266
48267                   if (lastToken && lastToken.type === 'text') {
48268                     lastToken.raw += '\n' + token.raw;
48269                     lastToken.text += '\n' + token.text;
48270                   } else {
48271                     tokens.push(token);
48272                   }
48273
48274                   continue;
48275                 }
48276
48277                 if (src) {
48278                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
48279
48280                   if (this.options.silent) {
48281                     console.error(errMsg);
48282                     break;
48283                   } else {
48284                     throw new Error(errMsg);
48285                   }
48286                 }
48287               }
48288
48289               return tokens;
48290             }
48291           }, {
48292             key: "inline",
48293             value: function inline(tokens) {
48294               var i, j, k, l2, row, token;
48295               var l = tokens.length;
48296
48297               for (i = 0; i < l; i++) {
48298                 token = tokens[i];
48299
48300                 switch (token.type) {
48301                   case 'paragraph':
48302                   case 'text':
48303                   case 'heading':
48304                     {
48305                       token.tokens = [];
48306                       this.inlineTokens(token.text, token.tokens);
48307                       break;
48308                     }
48309
48310                   case 'table':
48311                     {
48312                       token.tokens = {
48313                         header: [],
48314                         cells: []
48315                       }; // header
48316
48317                       l2 = token.header.length;
48318
48319                       for (j = 0; j < l2; j++) {
48320                         token.tokens.header[j] = [];
48321                         this.inlineTokens(token.header[j], token.tokens.header[j]);
48322                       } // cells
48323
48324
48325                       l2 = token.cells.length;
48326
48327                       for (j = 0; j < l2; j++) {
48328                         row = token.cells[j];
48329                         token.tokens.cells[j] = [];
48330
48331                         for (k = 0; k < row.length; k++) {
48332                           token.tokens.cells[j][k] = [];
48333                           this.inlineTokens(row[k], token.tokens.cells[j][k]);
48334                         }
48335                       }
48336
48337                       break;
48338                     }
48339
48340                   case 'blockquote':
48341                     {
48342                       this.inline(token.tokens);
48343                       break;
48344                     }
48345
48346                   case 'list':
48347                     {
48348                       l2 = token.items.length;
48349
48350                       for (j = 0; j < l2; j++) {
48351                         this.inline(token.items[j].tokens);
48352                       }
48353
48354                       break;
48355                     }
48356                 }
48357               }
48358
48359               return tokens;
48360             }
48361             /**
48362              * Lexing/Compiling
48363              */
48364
48365           }, {
48366             key: "inlineTokens",
48367             value: function inlineTokens(src) {
48368               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
48369               var inLink = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
48370               var inRawBlock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
48371               var token, lastToken; // String with links masked to avoid interference with em and strong
48372
48373               var maskedSrc = src;
48374               var match;
48375               var keepPrevChar, prevChar; // Mask out reflinks
48376
48377               if (this.tokens.links) {
48378                 var links = Object.keys(this.tokens.links);
48379
48380                 if (links.length > 0) {
48381                   while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
48382                     if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
48383                       maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
48384                     }
48385                   }
48386                 }
48387               } // Mask out other blocks
48388
48389
48390               while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
48391                 maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
48392               } // Mask out escaped em & strong delimiters
48393
48394
48395               while ((match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null) {
48396                 maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);
48397               }
48398
48399               while (src) {
48400                 if (!keepPrevChar) {
48401                   prevChar = '';
48402                 }
48403
48404                 keepPrevChar = false; // escape
48405
48406                 if (token = this.tokenizer.escape(src)) {
48407                   src = src.substring(token.raw.length);
48408                   tokens.push(token);
48409                   continue;
48410                 } // tag
48411
48412
48413                 if (token = this.tokenizer.tag(src, inLink, inRawBlock)) {
48414                   src = src.substring(token.raw.length);
48415                   inLink = token.inLink;
48416                   inRawBlock = token.inRawBlock;
48417                   var _lastToken = tokens[tokens.length - 1];
48418
48419                   if (_lastToken && token.type === 'text' && _lastToken.type === 'text') {
48420                     _lastToken.raw += token.raw;
48421                     _lastToken.text += token.text;
48422                   } else {
48423                     tokens.push(token);
48424                   }
48425
48426                   continue;
48427                 } // link
48428
48429
48430                 if (token = this.tokenizer.link(src)) {
48431                   src = src.substring(token.raw.length);
48432
48433                   if (token.type === 'link') {
48434                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
48435                   }
48436
48437                   tokens.push(token);
48438                   continue;
48439                 } // reflink, nolink
48440
48441
48442                 if (token = this.tokenizer.reflink(src, this.tokens.links)) {
48443                   src = src.substring(token.raw.length);
48444                   var _lastToken2 = tokens[tokens.length - 1];
48445
48446                   if (token.type === 'link') {
48447                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
48448                     tokens.push(token);
48449                   } else if (_lastToken2 && token.type === 'text' && _lastToken2.type === 'text') {
48450                     _lastToken2.raw += token.raw;
48451                     _lastToken2.text += token.text;
48452                   } else {
48453                     tokens.push(token);
48454                   }
48455
48456                   continue;
48457                 } // em & strong
48458
48459
48460                 if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
48461                   src = src.substring(token.raw.length);
48462                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
48463                   tokens.push(token);
48464                   continue;
48465                 } // code
48466
48467
48468                 if (token = this.tokenizer.codespan(src)) {
48469                   src = src.substring(token.raw.length);
48470                   tokens.push(token);
48471                   continue;
48472                 } // br
48473
48474
48475                 if (token = this.tokenizer.br(src)) {
48476                   src = src.substring(token.raw.length);
48477                   tokens.push(token);
48478                   continue;
48479                 } // del (gfm)
48480
48481
48482                 if (token = this.tokenizer.del(src)) {
48483                   src = src.substring(token.raw.length);
48484                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
48485                   tokens.push(token);
48486                   continue;
48487                 } // autolink
48488
48489
48490                 if (token = this.tokenizer.autolink(src, mangle)) {
48491                   src = src.substring(token.raw.length);
48492                   tokens.push(token);
48493                   continue;
48494                 } // url (gfm)
48495
48496
48497                 if (!inLink && (token = this.tokenizer.url(src, mangle))) {
48498                   src = src.substring(token.raw.length);
48499                   tokens.push(token);
48500                   continue;
48501                 } // text
48502
48503
48504                 if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
48505                   src = src.substring(token.raw.length);
48506
48507                   if (token.raw.slice(-1) !== '_') {
48508                     // Track prevChar before string of ____ started
48509                     prevChar = token.raw.slice(-1);
48510                   }
48511
48512                   keepPrevChar = true;
48513                   lastToken = tokens[tokens.length - 1];
48514
48515                   if (lastToken && lastToken.type === 'text') {
48516                     lastToken.raw += token.raw;
48517                     lastToken.text += token.text;
48518                   } else {
48519                     tokens.push(token);
48520                   }
48521
48522                   continue;
48523                 }
48524
48525                 if (src) {
48526                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
48527
48528                   if (this.options.silent) {
48529                     console.error(errMsg);
48530                     break;
48531                   } else {
48532                     throw new Error(errMsg);
48533                   }
48534                 }
48535               }
48536
48537               return tokens;
48538             }
48539           }], [{
48540             key: "rules",
48541             get: function get() {
48542               return {
48543                 block: block,
48544                 inline: inline
48545               };
48546             }
48547             /**
48548              * Static Lex Method
48549              */
48550
48551           }, {
48552             key: "lex",
48553             value: function lex(src, options) {
48554               var lexer = new Lexer(options);
48555               return lexer.lex(src);
48556             }
48557             /**
48558              * Static Lex Inline Method
48559              */
48560
48561           }, {
48562             key: "lexInline",
48563             value: function lexInline(src, options) {
48564               var lexer = new Lexer(options);
48565               return lexer.inlineTokens(src);
48566             }
48567           }]);
48568
48569           return Lexer;
48570         }();
48571
48572         var defaults$2 = defaults$5.defaults;
48573         var cleanUrl = helpers.cleanUrl,
48574             escape$2 = helpers.escape;
48575         /**
48576          * Renderer
48577          */
48578
48579         var Renderer_1 = /*#__PURE__*/function () {
48580           function Renderer(options) {
48581             _classCallCheck$1(this, Renderer);
48582
48583             this.options = options || defaults$2;
48584           }
48585
48586           _createClass$1(Renderer, [{
48587             key: "code",
48588             value: function code(_code, infostring, escaped) {
48589               var lang = (infostring || '').match(/\S*/)[0];
48590
48591               if (this.options.highlight) {
48592                 var out = this.options.highlight(_code, lang);
48593
48594                 if (out != null && out !== _code) {
48595                   escaped = true;
48596                   _code = out;
48597                 }
48598               }
48599
48600               _code = _code.replace(/\n$/, '') + '\n';
48601
48602               if (!lang) {
48603                 return '<pre><code>' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
48604               }
48605
48606               return '<pre><code class="' + this.options.langPrefix + escape$2(lang, true) + '">' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
48607             }
48608           }, {
48609             key: "blockquote",
48610             value: function blockquote(quote) {
48611               return '<blockquote>\n' + quote + '</blockquote>\n';
48612             }
48613           }, {
48614             key: "html",
48615             value: function html(_html) {
48616               return _html;
48617             }
48618           }, {
48619             key: "heading",
48620             value: function heading(text, level, raw, slugger) {
48621               if (this.options.headerIds) {
48622                 return '<h' + level + ' id="' + this.options.headerPrefix + slugger.slug(raw) + '">' + text + '</h' + level + '>\n';
48623               } // ignore IDs
48624
48625
48626               return '<h' + level + '>' + text + '</h' + level + '>\n';
48627             }
48628           }, {
48629             key: "hr",
48630             value: function hr() {
48631               return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
48632             }
48633           }, {
48634             key: "list",
48635             value: function list(body, ordered, start) {
48636               var type = ordered ? 'ol' : 'ul',
48637                   startatt = ordered && start !== 1 ? ' start="' + start + '"' : '';
48638               return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
48639             }
48640           }, {
48641             key: "listitem",
48642             value: function listitem(text) {
48643               return '<li>' + text + '</li>\n';
48644             }
48645           }, {
48646             key: "checkbox",
48647             value: function checkbox(checked) {
48648               return '<input ' + (checked ? 'checked="" ' : '') + 'disabled="" type="checkbox"' + (this.options.xhtml ? ' /' : '') + '> ';
48649             }
48650           }, {
48651             key: "paragraph",
48652             value: function paragraph(text) {
48653               return '<p>' + text + '</p>\n';
48654             }
48655           }, {
48656             key: "table",
48657             value: function table(header, body) {
48658               if (body) body = '<tbody>' + body + '</tbody>';
48659               return '<table>\n' + '<thead>\n' + header + '</thead>\n' + body + '</table>\n';
48660             }
48661           }, {
48662             key: "tablerow",
48663             value: function tablerow(content) {
48664               return '<tr>\n' + content + '</tr>\n';
48665             }
48666           }, {
48667             key: "tablecell",
48668             value: function tablecell(content, flags) {
48669               var type = flags.header ? 'th' : 'td';
48670               var tag = flags.align ? '<' + type + ' align="' + flags.align + '">' : '<' + type + '>';
48671               return tag + content + '</' + type + '>\n';
48672             } // span level renderer
48673
48674           }, {
48675             key: "strong",
48676             value: function strong(text) {
48677               return '<strong>' + text + '</strong>';
48678             }
48679           }, {
48680             key: "em",
48681             value: function em(text) {
48682               return '<em>' + text + '</em>';
48683             }
48684           }, {
48685             key: "codespan",
48686             value: function codespan(text) {
48687               return '<code>' + text + '</code>';
48688             }
48689           }, {
48690             key: "br",
48691             value: function br() {
48692               return this.options.xhtml ? '<br/>' : '<br>';
48693             }
48694           }, {
48695             key: "del",
48696             value: function del(text) {
48697               return '<del>' + text + '</del>';
48698             }
48699           }, {
48700             key: "link",
48701             value: function link(href, title, text) {
48702               href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
48703
48704               if (href === null) {
48705                 return text;
48706               }
48707
48708               var out = '<a href="' + escape$2(href) + '"';
48709
48710               if (title) {
48711                 out += ' title="' + title + '"';
48712               }
48713
48714               out += '>' + text + '</a>';
48715               return out;
48716             }
48717           }, {
48718             key: "image",
48719             value: function image(href, title, text) {
48720               href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
48721
48722               if (href === null) {
48723                 return text;
48724               }
48725
48726               var out = '<img src="' + href + '" alt="' + text + '"';
48727
48728               if (title) {
48729                 out += ' title="' + title + '"';
48730               }
48731
48732               out += this.options.xhtml ? '/>' : '>';
48733               return out;
48734             }
48735           }, {
48736             key: "text",
48737             value: function text(_text) {
48738               return _text;
48739             }
48740           }]);
48741
48742           return Renderer;
48743         }();
48744
48745         /**
48746          * TextRenderer
48747          * returns only the textual part of the token
48748          */
48749         var TextRenderer_1 = /*#__PURE__*/function () {
48750           function TextRenderer() {
48751             _classCallCheck$1(this, TextRenderer);
48752           }
48753
48754           _createClass$1(TextRenderer, [{
48755             key: "strong",
48756             value: // no need for block level renderers
48757             function strong(text) {
48758               return text;
48759             }
48760           }, {
48761             key: "em",
48762             value: function em(text) {
48763               return text;
48764             }
48765           }, {
48766             key: "codespan",
48767             value: function codespan(text) {
48768               return text;
48769             }
48770           }, {
48771             key: "del",
48772             value: function del(text) {
48773               return text;
48774             }
48775           }, {
48776             key: "html",
48777             value: function html(text) {
48778               return text;
48779             }
48780           }, {
48781             key: "text",
48782             value: function text(_text) {
48783               return _text;
48784             }
48785           }, {
48786             key: "link",
48787             value: function link(href, title, text) {
48788               return '' + text;
48789             }
48790           }, {
48791             key: "image",
48792             value: function image(href, title, text) {
48793               return '' + text;
48794             }
48795           }, {
48796             key: "br",
48797             value: function br() {
48798               return '';
48799             }
48800           }]);
48801
48802           return TextRenderer;
48803         }();
48804
48805         /**
48806          * Slugger generates header id
48807          */
48808         var Slugger_1 = /*#__PURE__*/function () {
48809           function Slugger() {
48810             _classCallCheck$1(this, Slugger);
48811
48812             this.seen = {};
48813           }
48814
48815           _createClass$1(Slugger, [{
48816             key: "serialize",
48817             value: function serialize(value) {
48818               return value.toLowerCase().trim() // remove html tags
48819               .replace(/<[!\/a-z].*?>/ig, '') // remove unwanted chars
48820               .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '').replace(/\s/g, '-');
48821             }
48822             /**
48823              * Finds the next safe (unique) slug to use
48824              */
48825
48826           }, {
48827             key: "getNextSafeSlug",
48828             value: function getNextSafeSlug(originalSlug, isDryRun) {
48829               var slug = originalSlug;
48830               var occurenceAccumulator = 0;
48831
48832               if (this.seen.hasOwnProperty(slug)) {
48833                 occurenceAccumulator = this.seen[originalSlug];
48834
48835                 do {
48836                   occurenceAccumulator++;
48837                   slug = originalSlug + '-' + occurenceAccumulator;
48838                 } while (this.seen.hasOwnProperty(slug));
48839               }
48840
48841               if (!isDryRun) {
48842                 this.seen[originalSlug] = occurenceAccumulator;
48843                 this.seen[slug] = 0;
48844               }
48845
48846               return slug;
48847             }
48848             /**
48849              * Convert string to unique id
48850              * @param {object} options
48851              * @param {boolean} options.dryrun Generates the next unique slug without updating the internal accumulator.
48852              */
48853
48854           }, {
48855             key: "slug",
48856             value: function slug(value) {
48857               var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
48858               var slug = this.serialize(value);
48859               return this.getNextSafeSlug(slug, options.dryrun);
48860             }
48861           }]);
48862
48863           return Slugger;
48864         }();
48865
48866         var defaults$1 = defaults$5.defaults;
48867         var unescape$1 = helpers.unescape;
48868         /**
48869          * Parsing & Compiling
48870          */
48871
48872         var Parser_1 = /*#__PURE__*/function () {
48873           function Parser(options) {
48874             _classCallCheck$1(this, Parser);
48875
48876             this.options = options || defaults$1;
48877             this.options.renderer = this.options.renderer || new Renderer_1();
48878             this.renderer = this.options.renderer;
48879             this.renderer.options = this.options;
48880             this.textRenderer = new TextRenderer_1();
48881             this.slugger = new Slugger_1();
48882           }
48883           /**
48884            * Static Parse Method
48885            */
48886
48887
48888           _createClass$1(Parser, [{
48889             key: "parse",
48890             value:
48891             /**
48892              * Parse Loop
48893              */
48894             function parse(tokens) {
48895               var top = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
48896               var out = '',
48897                   i,
48898                   j,
48899                   k,
48900                   l2,
48901                   l3,
48902                   row,
48903                   cell,
48904                   header,
48905                   body,
48906                   token,
48907                   ordered,
48908                   start,
48909                   loose,
48910                   itemBody,
48911                   item,
48912                   checked,
48913                   task,
48914                   checkbox;
48915               var l = tokens.length;
48916
48917               for (i = 0; i < l; i++) {
48918                 token = tokens[i];
48919
48920                 switch (token.type) {
48921                   case 'space':
48922                     {
48923                       continue;
48924                     }
48925
48926                   case 'hr':
48927                     {
48928                       out += this.renderer.hr();
48929                       continue;
48930                     }
48931
48932                   case 'heading':
48933                     {
48934                       out += this.renderer.heading(this.parseInline(token.tokens), token.depth, unescape$1(this.parseInline(token.tokens, this.textRenderer)), this.slugger);
48935                       continue;
48936                     }
48937
48938                   case 'code':
48939                     {
48940                       out += this.renderer.code(token.text, token.lang, token.escaped);
48941                       continue;
48942                     }
48943
48944                   case 'table':
48945                     {
48946                       header = ''; // header
48947
48948                       cell = '';
48949                       l2 = token.header.length;
48950
48951                       for (j = 0; j < l2; j++) {
48952                         cell += this.renderer.tablecell(this.parseInline(token.tokens.header[j]), {
48953                           header: true,
48954                           align: token.align[j]
48955                         });
48956                       }
48957
48958                       header += this.renderer.tablerow(cell);
48959                       body = '';
48960                       l2 = token.cells.length;
48961
48962                       for (j = 0; j < l2; j++) {
48963                         row = token.tokens.cells[j];
48964                         cell = '';
48965                         l3 = row.length;
48966
48967                         for (k = 0; k < l3; k++) {
48968                           cell += this.renderer.tablecell(this.parseInline(row[k]), {
48969                             header: false,
48970                             align: token.align[k]
48971                           });
48972                         }
48973
48974                         body += this.renderer.tablerow(cell);
48975                       }
48976
48977                       out += this.renderer.table(header, body);
48978                       continue;
48979                     }
48980
48981                   case 'blockquote':
48982                     {
48983                       body = this.parse(token.tokens);
48984                       out += this.renderer.blockquote(body);
48985                       continue;
48986                     }
48987
48988                   case 'list':
48989                     {
48990                       ordered = token.ordered;
48991                       start = token.start;
48992                       loose = token.loose;
48993                       l2 = token.items.length;
48994                       body = '';
48995
48996                       for (j = 0; j < l2; j++) {
48997                         item = token.items[j];
48998                         checked = item.checked;
48999                         task = item.task;
49000                         itemBody = '';
49001
49002                         if (item.task) {
49003                           checkbox = this.renderer.checkbox(checked);
49004
49005                           if (loose) {
49006                             if (item.tokens.length > 0 && item.tokens[0].type === 'text') {
49007                               item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
49008
49009                               if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
49010                                 item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
49011                               }
49012                             } else {
49013                               item.tokens.unshift({
49014                                 type: 'text',
49015                                 text: checkbox
49016                               });
49017                             }
49018                           } else {
49019                             itemBody += checkbox;
49020                           }
49021                         }
49022
49023                         itemBody += this.parse(item.tokens, loose);
49024                         body += this.renderer.listitem(itemBody, task, checked);
49025                       }
49026
49027                       out += this.renderer.list(body, ordered, start);
49028                       continue;
49029                     }
49030
49031                   case 'html':
49032                     {
49033                       // TODO parse inline content if parameter markdown=1
49034                       out += this.renderer.html(token.text);
49035                       continue;
49036                     }
49037
49038                   case 'paragraph':
49039                     {
49040                       out += this.renderer.paragraph(this.parseInline(token.tokens));
49041                       continue;
49042                     }
49043
49044                   case 'text':
49045                     {
49046                       body = token.tokens ? this.parseInline(token.tokens) : token.text;
49047
49048                       while (i + 1 < l && tokens[i + 1].type === 'text') {
49049                         token = tokens[++i];
49050                         body += '\n' + (token.tokens ? this.parseInline(token.tokens) : token.text);
49051                       }
49052
49053                       out += top ? this.renderer.paragraph(body) : body;
49054                       continue;
49055                     }
49056
49057                   default:
49058                     {
49059                       var errMsg = 'Token with "' + token.type + '" type was not found.';
49060
49061                       if (this.options.silent) {
49062                         console.error(errMsg);
49063                         return;
49064                       } else {
49065                         throw new Error(errMsg);
49066                       }
49067                     }
49068                 }
49069               }
49070
49071               return out;
49072             }
49073             /**
49074              * Parse Inline Tokens
49075              */
49076
49077           }, {
49078             key: "parseInline",
49079             value: function parseInline(tokens, renderer) {
49080               renderer = renderer || this.renderer;
49081               var out = '',
49082                   i,
49083                   token;
49084               var l = tokens.length;
49085
49086               for (i = 0; i < l; i++) {
49087                 token = tokens[i];
49088
49089                 switch (token.type) {
49090                   case 'escape':
49091                     {
49092                       out += renderer.text(token.text);
49093                       break;
49094                     }
49095
49096                   case 'html':
49097                     {
49098                       out += renderer.html(token.text);
49099                       break;
49100                     }
49101
49102                   case 'link':
49103                     {
49104                       out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
49105                       break;
49106                     }
49107
49108                   case 'image':
49109                     {
49110                       out += renderer.image(token.href, token.title, token.text);
49111                       break;
49112                     }
49113
49114                   case 'strong':
49115                     {
49116                       out += renderer.strong(this.parseInline(token.tokens, renderer));
49117                       break;
49118                     }
49119
49120                   case 'em':
49121                     {
49122                       out += renderer.em(this.parseInline(token.tokens, renderer));
49123                       break;
49124                     }
49125
49126                   case 'codespan':
49127                     {
49128                       out += renderer.codespan(token.text);
49129                       break;
49130                     }
49131
49132                   case 'br':
49133                     {
49134                       out += renderer.br();
49135                       break;
49136                     }
49137
49138                   case 'del':
49139                     {
49140                       out += renderer.del(this.parseInline(token.tokens, renderer));
49141                       break;
49142                     }
49143
49144                   case 'text':
49145                     {
49146                       out += renderer.text(token.text);
49147                       break;
49148                     }
49149
49150                   default:
49151                     {
49152                       var errMsg = 'Token with "' + token.type + '" type was not found.';
49153
49154                       if (this.options.silent) {
49155                         console.error(errMsg);
49156                         return;
49157                       } else {
49158                         throw new Error(errMsg);
49159                       }
49160                     }
49161                 }
49162               }
49163
49164               return out;
49165             }
49166           }], [{
49167             key: "parse",
49168             value: function parse(tokens, options) {
49169               var parser = new Parser(options);
49170               return parser.parse(tokens);
49171             }
49172             /**
49173              * Static Parse Inline Method
49174              */
49175
49176           }, {
49177             key: "parseInline",
49178             value: function parseInline(tokens, options) {
49179               var parser = new Parser(options);
49180               return parser.parseInline(tokens);
49181             }
49182           }]);
49183
49184           return Parser;
49185         }();
49186
49187         var merge = helpers.merge,
49188             checkSanitizeDeprecation = helpers.checkSanitizeDeprecation,
49189             escape$1 = helpers.escape;
49190         var getDefaults = defaults$5.getDefaults,
49191             changeDefaults = defaults$5.changeDefaults,
49192             defaults = defaults$5.defaults;
49193         /**
49194          * Marked
49195          */
49196
49197         function marked(src, opt, callback) {
49198           // throw error in case of non string input
49199           if (typeof src === 'undefined' || src === null) {
49200             throw new Error('marked(): input parameter is undefined or null');
49201           }
49202
49203           if (typeof src !== 'string') {
49204             throw new Error('marked(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
49205           }
49206
49207           if (typeof opt === 'function') {
49208             callback = opt;
49209             opt = null;
49210           }
49211
49212           opt = merge({}, marked.defaults, opt || {});
49213           checkSanitizeDeprecation(opt);
49214
49215           if (callback) {
49216             var highlight = opt.highlight;
49217             var tokens;
49218
49219             try {
49220               tokens = Lexer_1.lex(src, opt);
49221             } catch (e) {
49222               return callback(e);
49223             }
49224
49225             var done = function done(err) {
49226               var out;
49227
49228               if (!err) {
49229                 try {
49230                   if (opt.walkTokens) {
49231                     marked.walkTokens(tokens, opt.walkTokens);
49232                   }
49233
49234                   out = Parser_1.parse(tokens, opt);
49235                 } catch (e) {
49236                   err = e;
49237                 }
49238               }
49239
49240               opt.highlight = highlight;
49241               return err ? callback(err) : callback(null, out);
49242             };
49243
49244             if (!highlight || highlight.length < 3) {
49245               return done();
49246             }
49247
49248             delete opt.highlight;
49249             if (!tokens.length) return done();
49250             var pending = 0;
49251             marked.walkTokens(tokens, function (token) {
49252               if (token.type === 'code') {
49253                 pending++;
49254                 setTimeout(function () {
49255                   highlight(token.text, token.lang, function (err, code) {
49256                     if (err) {
49257                       return done(err);
49258                     }
49259
49260                     if (code != null && code !== token.text) {
49261                       token.text = code;
49262                       token.escaped = true;
49263                     }
49264
49265                     pending--;
49266
49267                     if (pending === 0) {
49268                       done();
49269                     }
49270                   });
49271                 }, 0);
49272               }
49273             });
49274
49275             if (pending === 0) {
49276               done();
49277             }
49278
49279             return;
49280           }
49281
49282           try {
49283             var _tokens = Lexer_1.lex(src, opt);
49284
49285             if (opt.walkTokens) {
49286               marked.walkTokens(_tokens, opt.walkTokens);
49287             }
49288
49289             return Parser_1.parse(_tokens, opt);
49290           } catch (e) {
49291             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
49292
49293             if (opt.silent) {
49294               return '<p>An error occurred:</p><pre>' + escape$1(e.message + '', true) + '</pre>';
49295             }
49296
49297             throw e;
49298           }
49299         }
49300         /**
49301          * Options
49302          */
49303
49304
49305         marked.options = marked.setOptions = function (opt) {
49306           merge(marked.defaults, opt);
49307           changeDefaults(marked.defaults);
49308           return marked;
49309         };
49310
49311         marked.getDefaults = getDefaults;
49312         marked.defaults = defaults;
49313         /**
49314          * Use Extension
49315          */
49316
49317         marked.use = function (extension) {
49318           var opts = merge({}, extension);
49319
49320           if (extension.renderer) {
49321             (function () {
49322               var renderer = marked.defaults.renderer || new Renderer_1();
49323
49324               var _loop = function _loop(prop) {
49325                 var prevRenderer = renderer[prop];
49326
49327                 renderer[prop] = function () {
49328                   for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
49329                     args[_key] = arguments[_key];
49330                   }
49331
49332                   var ret = extension.renderer[prop].apply(renderer, args);
49333
49334                   if (ret === false) {
49335                     ret = prevRenderer.apply(renderer, args);
49336                   }
49337
49338                   return ret;
49339                 };
49340               };
49341
49342               for (var prop in extension.renderer) {
49343                 _loop(prop);
49344               }
49345
49346               opts.renderer = renderer;
49347             })();
49348           }
49349
49350           if (extension.tokenizer) {
49351             (function () {
49352               var tokenizer = marked.defaults.tokenizer || new Tokenizer_1();
49353
49354               var _loop2 = function _loop2(prop) {
49355                 var prevTokenizer = tokenizer[prop];
49356
49357                 tokenizer[prop] = function () {
49358                   for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
49359                     args[_key2] = arguments[_key2];
49360                   }
49361
49362                   var ret = extension.tokenizer[prop].apply(tokenizer, args);
49363
49364                   if (ret === false) {
49365                     ret = prevTokenizer.apply(tokenizer, args);
49366                   }
49367
49368                   return ret;
49369                 };
49370               };
49371
49372               for (var prop in extension.tokenizer) {
49373                 _loop2(prop);
49374               }
49375
49376               opts.tokenizer = tokenizer;
49377             })();
49378           }
49379
49380           if (extension.walkTokens) {
49381             var walkTokens = marked.defaults.walkTokens;
49382
49383             opts.walkTokens = function (token) {
49384               extension.walkTokens(token);
49385
49386               if (walkTokens) {
49387                 walkTokens(token);
49388               }
49389             };
49390           }
49391
49392           marked.setOptions(opts);
49393         };
49394         /**
49395          * Run callback for every token
49396          */
49397
49398
49399         marked.walkTokens = function (tokens, callback) {
49400           var _iterator = _createForOfIteratorHelper(tokens),
49401               _step;
49402
49403           try {
49404             for (_iterator.s(); !(_step = _iterator.n()).done;) {
49405               var token = _step.value;
49406               callback(token);
49407
49408               switch (token.type) {
49409                 case 'table':
49410                   {
49411                     var _iterator2 = _createForOfIteratorHelper(token.tokens.header),
49412                         _step2;
49413
49414                     try {
49415                       for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
49416                         var cell = _step2.value;
49417                         marked.walkTokens(cell, callback);
49418                       }
49419                     } catch (err) {
49420                       _iterator2.e(err);
49421                     } finally {
49422                       _iterator2.f();
49423                     }
49424
49425                     var _iterator3 = _createForOfIteratorHelper(token.tokens.cells),
49426                         _step3;
49427
49428                     try {
49429                       for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
49430                         var row = _step3.value;
49431
49432                         var _iterator4 = _createForOfIteratorHelper(row),
49433                             _step4;
49434
49435                         try {
49436                           for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
49437                             var _cell = _step4.value;
49438                             marked.walkTokens(_cell, callback);
49439                           }
49440                         } catch (err) {
49441                           _iterator4.e(err);
49442                         } finally {
49443                           _iterator4.f();
49444                         }
49445                       }
49446                     } catch (err) {
49447                       _iterator3.e(err);
49448                     } finally {
49449                       _iterator3.f();
49450                     }
49451
49452                     break;
49453                   }
49454
49455                 case 'list':
49456                   {
49457                     marked.walkTokens(token.items, callback);
49458                     break;
49459                   }
49460
49461                 default:
49462                   {
49463                     if (token.tokens) {
49464                       marked.walkTokens(token.tokens, callback);
49465                     }
49466                   }
49467               }
49468             }
49469           } catch (err) {
49470             _iterator.e(err);
49471           } finally {
49472             _iterator.f();
49473           }
49474         };
49475         /**
49476          * Parse Inline
49477          */
49478
49479
49480         marked.parseInline = function (src, opt) {
49481           // throw error in case of non string input
49482           if (typeof src === 'undefined' || src === null) {
49483             throw new Error('marked.parseInline(): input parameter is undefined or null');
49484           }
49485
49486           if (typeof src !== 'string') {
49487             throw new Error('marked.parseInline(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
49488           }
49489
49490           opt = merge({}, marked.defaults, opt || {});
49491           checkSanitizeDeprecation(opt);
49492
49493           try {
49494             var tokens = Lexer_1.lexInline(src, opt);
49495
49496             if (opt.walkTokens) {
49497               marked.walkTokens(tokens, opt.walkTokens);
49498             }
49499
49500             return Parser_1.parseInline(tokens, opt);
49501           } catch (e) {
49502             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
49503
49504             if (opt.silent) {
49505               return '<p>An error occurred:</p><pre>' + escape$1(e.message + '', true) + '</pre>';
49506             }
49507
49508             throw e;
49509           }
49510         };
49511         /**
49512          * Expose
49513          */
49514
49515
49516         marked.Parser = Parser_1;
49517         marked.parser = Parser_1.parse;
49518         marked.Renderer = Renderer_1;
49519         marked.TextRenderer = TextRenderer_1;
49520         marked.Lexer = Lexer_1;
49521         marked.lexer = Lexer_1.lex;
49522         marked.Tokenizer = Tokenizer_1;
49523         marked.Slugger = Slugger_1;
49524         marked.parse = marked;
49525         var marked_1 = marked;
49526
49527         var tiler$4 = utilTiler();
49528         var dispatch$5 = dispatch$8('loaded');
49529         var _tileZoom$1 = 14;
49530         var _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/api/0.3';
49531         var _osmoseData = {
49532           icons: {},
49533           items: []
49534         }; // This gets reassigned if reset
49535
49536         var _cache;
49537
49538         function abortRequest$4(controller) {
49539           if (controller) {
49540             controller.abort();
49541           }
49542         }
49543
49544         function abortUnwantedRequests$1(cache, tiles) {
49545           Object.keys(cache.inflightTile).forEach(function (k) {
49546             var wanted = tiles.find(function (tile) {
49547               return k === tile.id;
49548             });
49549
49550             if (!wanted) {
49551               abortRequest$4(cache.inflightTile[k]);
49552               delete cache.inflightTile[k];
49553             }
49554           });
49555         }
49556
49557         function encodeIssueRtree(d) {
49558           return {
49559             minX: d.loc[0],
49560             minY: d.loc[1],
49561             maxX: d.loc[0],
49562             maxY: d.loc[1],
49563             data: d
49564           };
49565         } // Replace or remove QAItem from rtree
49566
49567
49568         function updateRtree$1(item, replace) {
49569           _cache.rtree.remove(item, function (a, b) {
49570             return a.data.id === b.data.id;
49571           });
49572
49573           if (replace) {
49574             _cache.rtree.insert(item);
49575           }
49576         } // Issues shouldn't obscure each other
49577
49578
49579         function preventCoincident(loc) {
49580           var coincident = false;
49581
49582           do {
49583             // first time, move marker up. after that, move marker right.
49584             var delta = coincident ? [0.00001, 0] : [0, 0.00001];
49585             loc = geoVecAdd(loc, delta);
49586             var bbox = geoExtent(loc).bbox();
49587             coincident = _cache.rtree.search(bbox).length;
49588           } while (coincident);
49589
49590           return loc;
49591         }
49592
49593         var serviceOsmose = {
49594           title: 'osmose',
49595           init: function init() {
49596             _mainFileFetcher.get('qa_data').then(function (d) {
49597               _osmoseData = d.osmose;
49598               _osmoseData.items = Object.keys(d.osmose.icons).map(function (s) {
49599                 return s.split('-')[0];
49600               }).reduce(function (unique, item) {
49601                 return unique.indexOf(item) !== -1 ? unique : [].concat(_toConsumableArray(unique), [item]);
49602               }, []);
49603             });
49604
49605             if (!_cache) {
49606               this.reset();
49607             }
49608
49609             this.event = utilRebind(this, dispatch$5, 'on');
49610           },
49611           reset: function reset() {
49612             var _strings = {};
49613             var _colors = {};
49614
49615             if (_cache) {
49616               Object.values(_cache.inflightTile).forEach(abortRequest$4); // Strings and colors are static and should not be re-populated
49617
49618               _strings = _cache.strings;
49619               _colors = _cache.colors;
49620             }
49621
49622             _cache = {
49623               data: {},
49624               loadedTile: {},
49625               inflightTile: {},
49626               inflightPost: {},
49627               closed: {},
49628               rtree: new RBush(),
49629               strings: _strings,
49630               colors: _colors
49631             };
49632           },
49633           loadIssues: function loadIssues(projection) {
49634             var _this = this;
49635
49636             var params = {
49637               // Tiles return a maximum # of issues
49638               // So we want to filter our request for only types iD supports
49639               item: _osmoseData.items
49640             }; // determine the needed tiles to cover the view
49641
49642             var tiles = tiler$4.zoomExtent([_tileZoom$1, _tileZoom$1]).getTiles(projection); // abort inflight requests that are no longer needed
49643
49644             abortUnwantedRequests$1(_cache, tiles); // issue new requests..
49645
49646             tiles.forEach(function (tile) {
49647               if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id]) return;
49648
49649               var _tile$xyz = _slicedToArray(tile.xyz, 3),
49650                   x = _tile$xyz[0],
49651                   y = _tile$xyz[1],
49652                   z = _tile$xyz[2];
49653
49654               var url = "".concat(_osmoseUrlRoot, "/issues/").concat(z, "/").concat(x, "/").concat(y, ".json?") + utilQsString(params);
49655               var controller = new AbortController();
49656               _cache.inflightTile[tile.id] = controller;
49657               d3_json(url, {
49658                 signal: controller.signal
49659               }).then(function (data) {
49660                 delete _cache.inflightTile[tile.id];
49661                 _cache.loadedTile[tile.id] = true;
49662
49663                 if (data.features) {
49664                   data.features.forEach(function (issue) {
49665                     var _issue$properties = issue.properties,
49666                         item = _issue$properties.item,
49667                         cl = _issue$properties["class"],
49668                         id = _issue$properties.uuid;
49669                     /* Osmose issues are uniquely identified by a unique
49670                       `item` and `class` combination (both integer values) */
49671
49672                     var itemType = "".concat(item, "-").concat(cl); // Filter out unsupported issue types (some are too specific or advanced)
49673
49674                     if (itemType in _osmoseData.icons) {
49675                       var loc = issue.geometry.coordinates; // lon, lat
49676
49677                       loc = preventCoincident(loc);
49678                       var d = new QAItem(loc, _this, itemType, id, {
49679                         item: item
49680                       }); // Setting elems here prevents UI detail requests
49681
49682                       if (item === 8300 || item === 8360) {
49683                         d.elems = [];
49684                       }
49685
49686                       _cache.data[d.id] = d;
49687
49688                       _cache.rtree.insert(encodeIssueRtree(d));
49689                     }
49690                   });
49691                 }
49692
49693                 dispatch$5.call('loaded');
49694               })["catch"](function () {
49695                 delete _cache.inflightTile[tile.id];
49696                 _cache.loadedTile[tile.id] = true;
49697               });
49698             });
49699           },
49700           loadIssueDetail: function loadIssueDetail(issue) {
49701             var _this2 = this;
49702
49703             // Issue details only need to be fetched once
49704             if (issue.elems !== undefined) {
49705               return Promise.resolve(issue);
49706             }
49707
49708             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "?langs=").concat(_mainLocalizer.localeCode());
49709
49710             var cacheDetails = function cacheDetails(data) {
49711               // Associated elements used for highlighting
49712               // Assign directly for immediate use in the callback
49713               issue.elems = data.elems.map(function (e) {
49714                 return e.type.substring(0, 1) + e.id;
49715               }); // Some issues have instance specific detail in a subtitle
49716
49717               issue.detail = data.subtitle ? marked_1(data.subtitle.auto) : '';
49718
49719               _this2.replaceItem(issue);
49720             };
49721
49722             return d3_json(url).then(cacheDetails).then(function () {
49723               return issue;
49724             });
49725           },
49726           loadStrings: function loadStrings() {
49727             var locale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _mainLocalizer.localeCode();
49728             var items = Object.keys(_osmoseData.icons);
49729
49730             if (locale in _cache.strings && Object.keys(_cache.strings[locale]).length === items.length) {
49731               return Promise.resolve(_cache.strings[locale]);
49732             } // May be partially populated already if some requests were successful
49733
49734
49735             if (!(locale in _cache.strings)) {
49736               _cache.strings[locale] = {};
49737             } // Only need to cache strings for supported issue types
49738             // Using multiple individual item + class requests to reduce fetched data size
49739
49740
49741             var allRequests = items.map(function (itemType) {
49742               // No need to request data we already have
49743               if (itemType in _cache.strings[locale]) return null;
49744
49745               var cacheData = function cacheData(data) {
49746                 // Bunch of nested single value arrays of objects
49747                 var _data$categories = _slicedToArray(data.categories, 1),
49748                     _data$categories$ = _data$categories[0],
49749                     cat = _data$categories$ === void 0 ? {
49750                   items: []
49751                 } : _data$categories$;
49752
49753                 var _cat$items = _slicedToArray(cat.items, 1),
49754                     _cat$items$ = _cat$items[0],
49755                     item = _cat$items$ === void 0 ? {
49756                   "class": []
49757                 } : _cat$items$;
49758
49759                 var _item$class = _slicedToArray(item["class"], 1),
49760                     _item$class$ = _item$class[0],
49761                     cl = _item$class$ === void 0 ? null : _item$class$; // If null default value is reached, data wasn't as expected (or was empty)
49762
49763
49764                 if (!cl) {
49765                   /* eslint-disable no-console */
49766                   console.log("Osmose strings request (".concat(itemType, ") had unexpected data"));
49767                   /* eslint-enable no-console */
49768
49769                   return;
49770                 } // Cache served item colors to automatically style issue markers later
49771
49772
49773                 var itemInt = item.item,
49774                     color = item.color;
49775
49776                 if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color)) {
49777                   _cache.colors[itemInt] = color;
49778                 } // Value of root key will be null if no string exists
49779                 // If string exists, value is an object with key 'auto' for string
49780
49781
49782                 var title = cl.title,
49783                     detail = cl.detail,
49784                     fix = cl.fix,
49785                     trap = cl.trap; // Osmose titles shouldn't contain markdown
49786
49787                 var issueStrings = {};
49788                 if (title) issueStrings.title = title.auto;
49789                 if (detail) issueStrings.detail = marked_1(detail.auto);
49790                 if (trap) issueStrings.trap = marked_1(trap.auto);
49791                 if (fix) issueStrings.fix = marked_1(fix.auto);
49792                 _cache.strings[locale][itemType] = issueStrings;
49793               };
49794
49795               var _itemType$split = itemType.split('-'),
49796                   _itemType$split2 = _slicedToArray(_itemType$split, 2),
49797                   item = _itemType$split2[0],
49798                   cl = _itemType$split2[1]; // Osmose API falls back to English strings where untranslated or if locale doesn't exist
49799
49800
49801               var url = "".concat(_osmoseUrlRoot, "/items/").concat(item, "/class/").concat(cl, "?langs=").concat(locale);
49802               return d3_json(url).then(cacheData);
49803             }).filter(Boolean);
49804             return Promise.all(allRequests).then(function () {
49805               return _cache.strings[locale];
49806             });
49807           },
49808           getStrings: function getStrings(itemType) {
49809             var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _mainLocalizer.localeCode();
49810             // No need to fallback to English, Osmose API handles this for us
49811             return locale in _cache.strings ? _cache.strings[locale][itemType] : {};
49812           },
49813           getColor: function getColor(itemType) {
49814             return itemType in _cache.colors ? _cache.colors[itemType] : '#FFFFFF';
49815           },
49816           postUpdate: function postUpdate(issue, callback) {
49817             var _this3 = this;
49818
49819             if (_cache.inflightPost[issue.id]) {
49820               return callback({
49821                 message: 'Issue update already inflight',
49822                 status: -2
49823               }, issue);
49824             } // UI sets the status to either 'done' or 'false'
49825
49826
49827             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "/").concat(issue.newStatus);
49828             var controller = new AbortController();
49829
49830             var after = function after() {
49831               delete _cache.inflightPost[issue.id];
49832
49833               _this3.removeItem(issue);
49834
49835               if (issue.newStatus === 'done') {
49836                 // Keep track of the number of issues closed per `item` to tag the changeset
49837                 if (!(issue.item in _cache.closed)) {
49838                   _cache.closed[issue.item] = 0;
49839                 }
49840
49841                 _cache.closed[issue.item] += 1;
49842               }
49843
49844               if (callback) callback(null, issue);
49845             };
49846
49847             _cache.inflightPost[issue.id] = controller;
49848             fetch(url, {
49849               signal: controller.signal
49850             }).then(after)["catch"](function (err) {
49851               delete _cache.inflightPost[issue.id];
49852               if (callback) callback(err.message);
49853             });
49854           },
49855           // Get all cached QAItems covering the viewport
49856           getItems: function getItems(projection) {
49857             var viewport = projection.clipExtent();
49858             var min = [viewport[0][0], viewport[1][1]];
49859             var max = [viewport[1][0], viewport[0][1]];
49860             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
49861             return _cache.rtree.search(bbox).map(function (d) {
49862               return d.data;
49863             });
49864           },
49865           // Get a QAItem from cache
49866           // NOTE: Don't change method name until UI v3 is merged
49867           getError: function getError(id) {
49868             return _cache.data[id];
49869           },
49870           // get the name of the icon to display for this item
49871           getIcon: function getIcon(itemType) {
49872             return _osmoseData.icons[itemType];
49873           },
49874           // Replace a single QAItem in the cache
49875           replaceItem: function replaceItem(item) {
49876             if (!(item instanceof QAItem) || !item.id) return;
49877             _cache.data[item.id] = item;
49878             updateRtree$1(encodeIssueRtree(item), true); // true = replace
49879
49880             return item;
49881           },
49882           // Remove a single QAItem from the cache
49883           removeItem: function removeItem(item) {
49884             if (!(item instanceof QAItem) || !item.id) return;
49885             delete _cache.data[item.id];
49886             updateRtree$1(encodeIssueRtree(item), false); // false = remove
49887           },
49888           // Used to populate `closed:osmose:*` changeset tags
49889           getClosedCounts: function getClosedCounts() {
49890             return _cache.closed;
49891           },
49892           itemURL: function itemURL(item) {
49893             return "https://osmose.openstreetmap.fr/en/error/".concat(item.id);
49894           }
49895         };
49896
49897         /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
49898         var read$6 = function read(buffer, offset, isLE, mLen, nBytes) {
49899           var e, m;
49900           var eLen = nBytes * 8 - mLen - 1;
49901           var eMax = (1 << eLen) - 1;
49902           var eBias = eMax >> 1;
49903           var nBits = -7;
49904           var i = isLE ? nBytes - 1 : 0;
49905           var d = isLE ? -1 : 1;
49906           var s = buffer[offset + i];
49907           i += d;
49908           e = s & (1 << -nBits) - 1;
49909           s >>= -nBits;
49910           nBits += eLen;
49911
49912           for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
49913
49914           m = e & (1 << -nBits) - 1;
49915           e >>= -nBits;
49916           nBits += mLen;
49917
49918           for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
49919
49920           if (e === 0) {
49921             e = 1 - eBias;
49922           } else if (e === eMax) {
49923             return m ? NaN : (s ? -1 : 1) * Infinity;
49924           } else {
49925             m = m + Math.pow(2, mLen);
49926             e = e - eBias;
49927           }
49928
49929           return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
49930         };
49931
49932         var write$6 = function write(buffer, value, offset, isLE, mLen, nBytes) {
49933           var e, m, c;
49934           var eLen = nBytes * 8 - mLen - 1;
49935           var eMax = (1 << eLen) - 1;
49936           var eBias = eMax >> 1;
49937           var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
49938           var i = isLE ? 0 : nBytes - 1;
49939           var d = isLE ? 1 : -1;
49940           var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
49941           value = Math.abs(value);
49942
49943           if (isNaN(value) || value === Infinity) {
49944             m = isNaN(value) ? 1 : 0;
49945             e = eMax;
49946           } else {
49947             e = Math.floor(Math.log(value) / Math.LN2);
49948
49949             if (value * (c = Math.pow(2, -e)) < 1) {
49950               e--;
49951               c *= 2;
49952             }
49953
49954             if (e + eBias >= 1) {
49955               value += rt / c;
49956             } else {
49957               value += rt * Math.pow(2, 1 - eBias);
49958             }
49959
49960             if (value * c >= 2) {
49961               e++;
49962               c /= 2;
49963             }
49964
49965             if (e + eBias >= eMax) {
49966               m = 0;
49967               e = eMax;
49968             } else if (e + eBias >= 1) {
49969               m = (value * c - 1) * Math.pow(2, mLen);
49970               e = e + eBias;
49971             } else {
49972               m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
49973               e = 0;
49974             }
49975           }
49976
49977           for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
49978
49979           e = e << mLen | m;
49980           eLen += mLen;
49981
49982           for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
49983
49984           buffer[offset + i - d] |= s * 128;
49985         };
49986
49987         var ieee754 = {
49988           read: read$6,
49989           write: write$6
49990         };
49991
49992         var pbf = Pbf;
49993
49994         function Pbf(buf) {
49995           this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
49996           this.pos = 0;
49997           this.type = 0;
49998           this.length = this.buf.length;
49999         }
50000
50001         Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
50002
50003         Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
50004
50005         Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
50006
50007         Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
50008
50009         var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
50010             SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; // Threshold chosen based on both benchmarking and knowledge about browser string
50011         // data structures (which currently switch structure types at 12 bytes or more)
50012
50013         var TEXT_DECODER_MIN_LENGTH = 12;
50014         var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
50015         Pbf.prototype = {
50016           destroy: function destroy() {
50017             this.buf = null;
50018           },
50019           // === READING =================================================================
50020           readFields: function readFields(readField, result, end) {
50021             end = end || this.length;
50022
50023             while (this.pos < end) {
50024               var val = this.readVarint(),
50025                   tag = val >> 3,
50026                   startPos = this.pos;
50027               this.type = val & 0x7;
50028               readField(tag, result, this);
50029               if (this.pos === startPos) this.skip(val);
50030             }
50031
50032             return result;
50033           },
50034           readMessage: function readMessage(readField, result) {
50035             return this.readFields(readField, result, this.readVarint() + this.pos);
50036           },
50037           readFixed32: function readFixed32() {
50038             var val = readUInt32(this.buf, this.pos);
50039             this.pos += 4;
50040             return val;
50041           },
50042           readSFixed32: function readSFixed32() {
50043             var val = readInt32(this.buf, this.pos);
50044             this.pos += 4;
50045             return val;
50046           },
50047           // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
50048           readFixed64: function readFixed64() {
50049             var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50050             this.pos += 8;
50051             return val;
50052           },
50053           readSFixed64: function readSFixed64() {
50054             var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50055             this.pos += 8;
50056             return val;
50057           },
50058           readFloat: function readFloat() {
50059             var val = ieee754.read(this.buf, this.pos, true, 23, 4);
50060             this.pos += 4;
50061             return val;
50062           },
50063           readDouble: function readDouble() {
50064             var val = ieee754.read(this.buf, this.pos, true, 52, 8);
50065             this.pos += 8;
50066             return val;
50067           },
50068           readVarint: function readVarint(isSigned) {
50069             var buf = this.buf,
50070                 val,
50071                 b;
50072             b = buf[this.pos++];
50073             val = b & 0x7f;
50074             if (b < 0x80) return val;
50075             b = buf[this.pos++];
50076             val |= (b & 0x7f) << 7;
50077             if (b < 0x80) return val;
50078             b = buf[this.pos++];
50079             val |= (b & 0x7f) << 14;
50080             if (b < 0x80) return val;
50081             b = buf[this.pos++];
50082             val |= (b & 0x7f) << 21;
50083             if (b < 0x80) return val;
50084             b = buf[this.pos];
50085             val |= (b & 0x0f) << 28;
50086             return readVarintRemainder(val, isSigned, this);
50087           },
50088           readVarint64: function readVarint64() {
50089             // for compatibility with v2.0.1
50090             return this.readVarint(true);
50091           },
50092           readSVarint: function readSVarint() {
50093             var num = this.readVarint();
50094             return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
50095           },
50096           readBoolean: function readBoolean() {
50097             return Boolean(this.readVarint());
50098           },
50099           readString: function readString() {
50100             var end = this.readVarint() + this.pos;
50101             var pos = this.pos;
50102             this.pos = end;
50103
50104             if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
50105               // longer strings are fast with the built-in browser TextDecoder API
50106               return readUtf8TextDecoder(this.buf, pos, end);
50107             } // short strings are fast with our custom implementation
50108
50109
50110             return readUtf8(this.buf, pos, end);
50111           },
50112           readBytes: function readBytes() {
50113             var end = this.readVarint() + this.pos,
50114                 buffer = this.buf.subarray(this.pos, end);
50115             this.pos = end;
50116             return buffer;
50117           },
50118           // verbose for performance reasons; doesn't affect gzipped size
50119           readPackedVarint: function readPackedVarint(arr, isSigned) {
50120             if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
50121             var end = readPackedEnd(this);
50122             arr = arr || [];
50123
50124             while (this.pos < end) {
50125               arr.push(this.readVarint(isSigned));
50126             }
50127
50128             return arr;
50129           },
50130           readPackedSVarint: function readPackedSVarint(arr) {
50131             if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
50132             var end = readPackedEnd(this);
50133             arr = arr || [];
50134
50135             while (this.pos < end) {
50136               arr.push(this.readSVarint());
50137             }
50138
50139             return arr;
50140           },
50141           readPackedBoolean: function readPackedBoolean(arr) {
50142             if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
50143             var end = readPackedEnd(this);
50144             arr = arr || [];
50145
50146             while (this.pos < end) {
50147               arr.push(this.readBoolean());
50148             }
50149
50150             return arr;
50151           },
50152           readPackedFloat: function readPackedFloat(arr) {
50153             if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
50154             var end = readPackedEnd(this);
50155             arr = arr || [];
50156
50157             while (this.pos < end) {
50158               arr.push(this.readFloat());
50159             }
50160
50161             return arr;
50162           },
50163           readPackedDouble: function readPackedDouble(arr) {
50164             if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
50165             var end = readPackedEnd(this);
50166             arr = arr || [];
50167
50168             while (this.pos < end) {
50169               arr.push(this.readDouble());
50170             }
50171
50172             return arr;
50173           },
50174           readPackedFixed32: function readPackedFixed32(arr) {
50175             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
50176             var end = readPackedEnd(this);
50177             arr = arr || [];
50178
50179             while (this.pos < end) {
50180               arr.push(this.readFixed32());
50181             }
50182
50183             return arr;
50184           },
50185           readPackedSFixed32: function readPackedSFixed32(arr) {
50186             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
50187             var end = readPackedEnd(this);
50188             arr = arr || [];
50189
50190             while (this.pos < end) {
50191               arr.push(this.readSFixed32());
50192             }
50193
50194             return arr;
50195           },
50196           readPackedFixed64: function readPackedFixed64(arr) {
50197             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
50198             var end = readPackedEnd(this);
50199             arr = arr || [];
50200
50201             while (this.pos < end) {
50202               arr.push(this.readFixed64());
50203             }
50204
50205             return arr;
50206           },
50207           readPackedSFixed64: function readPackedSFixed64(arr) {
50208             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
50209             var end = readPackedEnd(this);
50210             arr = arr || [];
50211
50212             while (this.pos < end) {
50213               arr.push(this.readSFixed64());
50214             }
50215
50216             return arr;
50217           },
50218           skip: function skip(val) {
50219             var type = val & 0x7;
50220             if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos;else if (type === Pbf.Fixed32) this.pos += 4;else if (type === Pbf.Fixed64) this.pos += 8;else throw new Error('Unimplemented type: ' + type);
50221           },
50222           // === WRITING =================================================================
50223           writeTag: function writeTag(tag, type) {
50224             this.writeVarint(tag << 3 | type);
50225           },
50226           realloc: function realloc(min) {
50227             var length = this.length || 16;
50228
50229             while (length < this.pos + min) {
50230               length *= 2;
50231             }
50232
50233             if (length !== this.length) {
50234               var buf = new Uint8Array(length);
50235               buf.set(this.buf);
50236               this.buf = buf;
50237               this.length = length;
50238             }
50239           },
50240           finish: function finish() {
50241             this.length = this.pos;
50242             this.pos = 0;
50243             return this.buf.subarray(0, this.length);
50244           },
50245           writeFixed32: function writeFixed32(val) {
50246             this.realloc(4);
50247             writeInt32(this.buf, val, this.pos);
50248             this.pos += 4;
50249           },
50250           writeSFixed32: function writeSFixed32(val) {
50251             this.realloc(4);
50252             writeInt32(this.buf, val, this.pos);
50253             this.pos += 4;
50254           },
50255           writeFixed64: function writeFixed64(val) {
50256             this.realloc(8);
50257             writeInt32(this.buf, val & -1, this.pos);
50258             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
50259             this.pos += 8;
50260           },
50261           writeSFixed64: function writeSFixed64(val) {
50262             this.realloc(8);
50263             writeInt32(this.buf, val & -1, this.pos);
50264             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
50265             this.pos += 8;
50266           },
50267           writeVarint: function writeVarint(val) {
50268             val = +val || 0;
50269
50270             if (val > 0xfffffff || val < 0) {
50271               writeBigVarint(val, this);
50272               return;
50273             }
50274
50275             this.realloc(4);
50276             this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0);
50277             if (val <= 0x7f) return;
50278             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
50279             if (val <= 0x7f) return;
50280             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
50281             if (val <= 0x7f) return;
50282             this.buf[this.pos++] = val >>> 7 & 0x7f;
50283           },
50284           writeSVarint: function writeSVarint(val) {
50285             this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
50286           },
50287           writeBoolean: function writeBoolean(val) {
50288             this.writeVarint(Boolean(val));
50289           },
50290           writeString: function writeString(str) {
50291             str = String(str);
50292             this.realloc(str.length * 4);
50293             this.pos++; // reserve 1 byte for short string length
50294
50295             var startPos = this.pos; // write the string directly to the buffer and see how much was written
50296
50297             this.pos = writeUtf8(this.buf, str, this.pos);
50298             var len = this.pos - startPos;
50299             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
50300
50301             this.pos = startPos - 1;
50302             this.writeVarint(len);
50303             this.pos += len;
50304           },
50305           writeFloat: function writeFloat(val) {
50306             this.realloc(4);
50307             ieee754.write(this.buf, val, this.pos, true, 23, 4);
50308             this.pos += 4;
50309           },
50310           writeDouble: function writeDouble(val) {
50311             this.realloc(8);
50312             ieee754.write(this.buf, val, this.pos, true, 52, 8);
50313             this.pos += 8;
50314           },
50315           writeBytes: function writeBytes(buffer) {
50316             var len = buffer.length;
50317             this.writeVarint(len);
50318             this.realloc(len);
50319
50320             for (var i = 0; i < len; i++) {
50321               this.buf[this.pos++] = buffer[i];
50322             }
50323           },
50324           writeRawMessage: function writeRawMessage(fn, obj) {
50325             this.pos++; // reserve 1 byte for short message length
50326             // write the message directly to the buffer and see how much was written
50327
50328             var startPos = this.pos;
50329             fn(obj, this);
50330             var len = this.pos - startPos;
50331             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
50332
50333             this.pos = startPos - 1;
50334             this.writeVarint(len);
50335             this.pos += len;
50336           },
50337           writeMessage: function writeMessage(tag, fn, obj) {
50338             this.writeTag(tag, Pbf.Bytes);
50339             this.writeRawMessage(fn, obj);
50340           },
50341           writePackedVarint: function writePackedVarint(tag, arr) {
50342             if (arr.length) this.writeMessage(tag, _writePackedVarint, arr);
50343           },
50344           writePackedSVarint: function writePackedSVarint(tag, arr) {
50345             if (arr.length) this.writeMessage(tag, _writePackedSVarint, arr);
50346           },
50347           writePackedBoolean: function writePackedBoolean(tag, arr) {
50348             if (arr.length) this.writeMessage(tag, _writePackedBoolean, arr);
50349           },
50350           writePackedFloat: function writePackedFloat(tag, arr) {
50351             if (arr.length) this.writeMessage(tag, _writePackedFloat, arr);
50352           },
50353           writePackedDouble: function writePackedDouble(tag, arr) {
50354             if (arr.length) this.writeMessage(tag, _writePackedDouble, arr);
50355           },
50356           writePackedFixed32: function writePackedFixed32(tag, arr) {
50357             if (arr.length) this.writeMessage(tag, _writePackedFixed, arr);
50358           },
50359           writePackedSFixed32: function writePackedSFixed32(tag, arr) {
50360             if (arr.length) this.writeMessage(tag, _writePackedSFixed, arr);
50361           },
50362           writePackedFixed64: function writePackedFixed64(tag, arr) {
50363             if (arr.length) this.writeMessage(tag, _writePackedFixed2, arr);
50364           },
50365           writePackedSFixed64: function writePackedSFixed64(tag, arr) {
50366             if (arr.length) this.writeMessage(tag, _writePackedSFixed2, arr);
50367           },
50368           writeBytesField: function writeBytesField(tag, buffer) {
50369             this.writeTag(tag, Pbf.Bytes);
50370             this.writeBytes(buffer);
50371           },
50372           writeFixed32Field: function writeFixed32Field(tag, val) {
50373             this.writeTag(tag, Pbf.Fixed32);
50374             this.writeFixed32(val);
50375           },
50376           writeSFixed32Field: function writeSFixed32Field(tag, val) {
50377             this.writeTag(tag, Pbf.Fixed32);
50378             this.writeSFixed32(val);
50379           },
50380           writeFixed64Field: function writeFixed64Field(tag, val) {
50381             this.writeTag(tag, Pbf.Fixed64);
50382             this.writeFixed64(val);
50383           },
50384           writeSFixed64Field: function writeSFixed64Field(tag, val) {
50385             this.writeTag(tag, Pbf.Fixed64);
50386             this.writeSFixed64(val);
50387           },
50388           writeVarintField: function writeVarintField(tag, val) {
50389             this.writeTag(tag, Pbf.Varint);
50390             this.writeVarint(val);
50391           },
50392           writeSVarintField: function writeSVarintField(tag, val) {
50393             this.writeTag(tag, Pbf.Varint);
50394             this.writeSVarint(val);
50395           },
50396           writeStringField: function writeStringField(tag, str) {
50397             this.writeTag(tag, Pbf.Bytes);
50398             this.writeString(str);
50399           },
50400           writeFloatField: function writeFloatField(tag, val) {
50401             this.writeTag(tag, Pbf.Fixed32);
50402             this.writeFloat(val);
50403           },
50404           writeDoubleField: function writeDoubleField(tag, val) {
50405             this.writeTag(tag, Pbf.Fixed64);
50406             this.writeDouble(val);
50407           },
50408           writeBooleanField: function writeBooleanField(tag, val) {
50409             this.writeVarintField(tag, Boolean(val));
50410           }
50411         };
50412
50413         function readVarintRemainder(l, s, p) {
50414           var buf = p.buf,
50415               h,
50416               b;
50417           b = buf[p.pos++];
50418           h = (b & 0x70) >> 4;
50419           if (b < 0x80) return toNum(l, h, s);
50420           b = buf[p.pos++];
50421           h |= (b & 0x7f) << 3;
50422           if (b < 0x80) return toNum(l, h, s);
50423           b = buf[p.pos++];
50424           h |= (b & 0x7f) << 10;
50425           if (b < 0x80) return toNum(l, h, s);
50426           b = buf[p.pos++];
50427           h |= (b & 0x7f) << 17;
50428           if (b < 0x80) return toNum(l, h, s);
50429           b = buf[p.pos++];
50430           h |= (b & 0x7f) << 24;
50431           if (b < 0x80) return toNum(l, h, s);
50432           b = buf[p.pos++];
50433           h |= (b & 0x01) << 31;
50434           if (b < 0x80) return toNum(l, h, s);
50435           throw new Error('Expected varint not more than 10 bytes');
50436         }
50437
50438         function readPackedEnd(pbf) {
50439           return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
50440         }
50441
50442         function toNum(low, high, isSigned) {
50443           if (isSigned) {
50444             return high * 0x100000000 + (low >>> 0);
50445           }
50446
50447           return (high >>> 0) * 0x100000000 + (low >>> 0);
50448         }
50449
50450         function writeBigVarint(val, pbf) {
50451           var low, high;
50452
50453           if (val >= 0) {
50454             low = val % 0x100000000 | 0;
50455             high = val / 0x100000000 | 0;
50456           } else {
50457             low = ~(-val % 0x100000000);
50458             high = ~(-val / 0x100000000);
50459
50460             if (low ^ 0xffffffff) {
50461               low = low + 1 | 0;
50462             } else {
50463               low = 0;
50464               high = high + 1 | 0;
50465             }
50466           }
50467
50468           if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
50469             throw new Error('Given varint doesn\'t fit into 10 bytes');
50470           }
50471
50472           pbf.realloc(10);
50473           writeBigVarintLow(low, high, pbf);
50474           writeBigVarintHigh(high, pbf);
50475         }
50476
50477         function writeBigVarintLow(low, high, pbf) {
50478           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
50479           low >>>= 7;
50480           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
50481           low >>>= 7;
50482           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
50483           low >>>= 7;
50484           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
50485           low >>>= 7;
50486           pbf.buf[pbf.pos] = low & 0x7f;
50487         }
50488
50489         function writeBigVarintHigh(high, pbf) {
50490           var lsb = (high & 0x07) << 4;
50491           pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0);
50492           if (!high) return;
50493           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
50494           if (!high) return;
50495           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
50496           if (!high) return;
50497           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
50498           if (!high) return;
50499           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
50500           if (!high) return;
50501           pbf.buf[pbf.pos++] = high & 0x7f;
50502         }
50503
50504         function makeRoomForExtraLength(startPos, len, pbf) {
50505           var extraLen = len <= 0x3fff ? 1 : len <= 0x1fffff ? 2 : len <= 0xfffffff ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7)); // if 1 byte isn't enough for encoding message length, shift the data to the right
50506
50507           pbf.realloc(extraLen);
50508
50509           for (var i = pbf.pos - 1; i >= startPos; i--) {
50510             pbf.buf[i + extraLen] = pbf.buf[i];
50511           }
50512         }
50513
50514         function _writePackedVarint(arr, pbf) {
50515           for (var i = 0; i < arr.length; i++) {
50516             pbf.writeVarint(arr[i]);
50517           }
50518         }
50519
50520         function _writePackedSVarint(arr, pbf) {
50521           for (var i = 0; i < arr.length; i++) {
50522             pbf.writeSVarint(arr[i]);
50523           }
50524         }
50525
50526         function _writePackedFloat(arr, pbf) {
50527           for (var i = 0; i < arr.length; i++) {
50528             pbf.writeFloat(arr[i]);
50529           }
50530         }
50531
50532         function _writePackedDouble(arr, pbf) {
50533           for (var i = 0; i < arr.length; i++) {
50534             pbf.writeDouble(arr[i]);
50535           }
50536         }
50537
50538         function _writePackedBoolean(arr, pbf) {
50539           for (var i = 0; i < arr.length; i++) {
50540             pbf.writeBoolean(arr[i]);
50541           }
50542         }
50543
50544         function _writePackedFixed(arr, pbf) {
50545           for (var i = 0; i < arr.length; i++) {
50546             pbf.writeFixed32(arr[i]);
50547           }
50548         }
50549
50550         function _writePackedSFixed(arr, pbf) {
50551           for (var i = 0; i < arr.length; i++) {
50552             pbf.writeSFixed32(arr[i]);
50553           }
50554         }
50555
50556         function _writePackedFixed2(arr, pbf) {
50557           for (var i = 0; i < arr.length; i++) {
50558             pbf.writeFixed64(arr[i]);
50559           }
50560         }
50561
50562         function _writePackedSFixed2(arr, pbf) {
50563           for (var i = 0; i < arr.length; i++) {
50564             pbf.writeSFixed64(arr[i]);
50565           }
50566         } // Buffer code below from https://github.com/feross/buffer, MIT-licensed
50567
50568
50569         function readUInt32(buf, pos) {
50570           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 0x1000000;
50571         }
50572
50573         function writeInt32(buf, val, pos) {
50574           buf[pos] = val;
50575           buf[pos + 1] = val >>> 8;
50576           buf[pos + 2] = val >>> 16;
50577           buf[pos + 3] = val >>> 24;
50578         }
50579
50580         function readInt32(buf, pos) {
50581           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
50582         }
50583
50584         function readUtf8(buf, pos, end) {
50585           var str = '';
50586           var i = pos;
50587
50588           while (i < end) {
50589             var b0 = buf[i];
50590             var c = null; // codepoint
50591
50592             var bytesPerSequence = b0 > 0xEF ? 4 : b0 > 0xDF ? 3 : b0 > 0xBF ? 2 : 1;
50593             if (i + bytesPerSequence > end) break;
50594             var b1, b2, b3;
50595
50596             if (bytesPerSequence === 1) {
50597               if (b0 < 0x80) {
50598                 c = b0;
50599               }
50600             } else if (bytesPerSequence === 2) {
50601               b1 = buf[i + 1];
50602
50603               if ((b1 & 0xC0) === 0x80) {
50604                 c = (b0 & 0x1F) << 0x6 | b1 & 0x3F;
50605
50606                 if (c <= 0x7F) {
50607                   c = null;
50608                 }
50609               }
50610             } else if (bytesPerSequence === 3) {
50611               b1 = buf[i + 1];
50612               b2 = buf[i + 2];
50613
50614               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
50615                 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | b2 & 0x3F;
50616
50617                 if (c <= 0x7FF || c >= 0xD800 && c <= 0xDFFF) {
50618                   c = null;
50619                 }
50620               }
50621             } else if (bytesPerSequence === 4) {
50622               b1 = buf[i + 1];
50623               b2 = buf[i + 2];
50624               b3 = buf[i + 3];
50625
50626               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
50627                 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | b3 & 0x3F;
50628
50629                 if (c <= 0xFFFF || c >= 0x110000) {
50630                   c = null;
50631                 }
50632               }
50633             }
50634
50635             if (c === null) {
50636               c = 0xFFFD;
50637               bytesPerSequence = 1;
50638             } else if (c > 0xFFFF) {
50639               c -= 0x10000;
50640               str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
50641               c = 0xDC00 | c & 0x3FF;
50642             }
50643
50644             str += String.fromCharCode(c);
50645             i += bytesPerSequence;
50646           }
50647
50648           return str;
50649         }
50650
50651         function readUtf8TextDecoder(buf, pos, end) {
50652           return utf8TextDecoder.decode(buf.subarray(pos, end));
50653         }
50654
50655         function writeUtf8(buf, str, pos) {
50656           for (var i = 0, c, lead; i < str.length; i++) {
50657             c = str.charCodeAt(i); // code point
50658
50659             if (c > 0xD7FF && c < 0xE000) {
50660               if (lead) {
50661                 if (c < 0xDC00) {
50662                   buf[pos++] = 0xEF;
50663                   buf[pos++] = 0xBF;
50664                   buf[pos++] = 0xBD;
50665                   lead = c;
50666                   continue;
50667                 } else {
50668                   c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
50669                   lead = null;
50670                 }
50671               } else {
50672                 if (c > 0xDBFF || i + 1 === str.length) {
50673                   buf[pos++] = 0xEF;
50674                   buf[pos++] = 0xBF;
50675                   buf[pos++] = 0xBD;
50676                 } else {
50677                   lead = c;
50678                 }
50679
50680                 continue;
50681               }
50682             } else if (lead) {
50683               buf[pos++] = 0xEF;
50684               buf[pos++] = 0xBF;
50685               buf[pos++] = 0xBD;
50686               lead = null;
50687             }
50688
50689             if (c < 0x80) {
50690               buf[pos++] = c;
50691             } else {
50692               if (c < 0x800) {
50693                 buf[pos++] = c >> 0x6 | 0xC0;
50694               } else {
50695                 if (c < 0x10000) {
50696                   buf[pos++] = c >> 0xC | 0xE0;
50697                 } else {
50698                   buf[pos++] = c >> 0x12 | 0xF0;
50699                   buf[pos++] = c >> 0xC & 0x3F | 0x80;
50700                 }
50701
50702                 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
50703               }
50704
50705               buf[pos++] = c & 0x3F | 0x80;
50706             }
50707           }
50708
50709           return pos;
50710         }
50711
50712         var pointGeometry = Point;
50713         /**
50714          * A standalone point geometry with useful accessor, comparison, and
50715          * modification methods.
50716          *
50717          * @class Point
50718          * @param {Number} x the x-coordinate. this could be longitude or screen
50719          * pixels, or any other sort of unit.
50720          * @param {Number} y the y-coordinate. this could be latitude or screen
50721          * pixels, or any other sort of unit.
50722          * @example
50723          * var point = new Point(-77, 38);
50724          */
50725
50726         function Point(x, y) {
50727           this.x = x;
50728           this.y = y;
50729         }
50730
50731         Point.prototype = {
50732           /**
50733            * Clone this point, returning a new point that can be modified
50734            * without affecting the old one.
50735            * @return {Point} the clone
50736            */
50737           clone: function clone() {
50738             return new Point(this.x, this.y);
50739           },
50740
50741           /**
50742            * Add this point's x & y coordinates to another point,
50743            * yielding a new point.
50744            * @param {Point} p the other point
50745            * @return {Point} output point
50746            */
50747           add: function add(p) {
50748             return this.clone()._add(p);
50749           },
50750
50751           /**
50752            * Subtract this point's x & y coordinates to from point,
50753            * yielding a new point.
50754            * @param {Point} p the other point
50755            * @return {Point} output point
50756            */
50757           sub: function sub(p) {
50758             return this.clone()._sub(p);
50759           },
50760
50761           /**
50762            * Multiply this point's x & y coordinates by point,
50763            * yielding a new point.
50764            * @param {Point} p the other point
50765            * @return {Point} output point
50766            */
50767           multByPoint: function multByPoint(p) {
50768             return this.clone()._multByPoint(p);
50769           },
50770
50771           /**
50772            * Divide this point's x & y coordinates by point,
50773            * yielding a new point.
50774            * @param {Point} p the other point
50775            * @return {Point} output point
50776            */
50777           divByPoint: function divByPoint(p) {
50778             return this.clone()._divByPoint(p);
50779           },
50780
50781           /**
50782            * Multiply this point's x & y coordinates by a factor,
50783            * yielding a new point.
50784            * @param {Point} k factor
50785            * @return {Point} output point
50786            */
50787           mult: function mult(k) {
50788             return this.clone()._mult(k);
50789           },
50790
50791           /**
50792            * Divide this point's x & y coordinates by a factor,
50793            * yielding a new point.
50794            * @param {Point} k factor
50795            * @return {Point} output point
50796            */
50797           div: function div(k) {
50798             return this.clone()._div(k);
50799           },
50800
50801           /**
50802            * Rotate this point around the 0, 0 origin by an angle a,
50803            * given in radians
50804            * @param {Number} a angle to rotate around, in radians
50805            * @return {Point} output point
50806            */
50807           rotate: function rotate(a) {
50808             return this.clone()._rotate(a);
50809           },
50810
50811           /**
50812            * Rotate this point around p point by an angle a,
50813            * given in radians
50814            * @param {Number} a angle to rotate around, in radians
50815            * @param {Point} p Point to rotate around
50816            * @return {Point} output point
50817            */
50818           rotateAround: function rotateAround(a, p) {
50819             return this.clone()._rotateAround(a, p);
50820           },
50821
50822           /**
50823            * Multiply this point by a 4x1 transformation matrix
50824            * @param {Array<Number>} m transformation matrix
50825            * @return {Point} output point
50826            */
50827           matMult: function matMult(m) {
50828             return this.clone()._matMult(m);
50829           },
50830
50831           /**
50832            * Calculate this point but as a unit vector from 0, 0, meaning
50833            * that the distance from the resulting point to the 0, 0
50834            * coordinate will be equal to 1 and the angle from the resulting
50835            * point to the 0, 0 coordinate will be the same as before.
50836            * @return {Point} unit vector point
50837            */
50838           unit: function unit() {
50839             return this.clone()._unit();
50840           },
50841
50842           /**
50843            * Compute a perpendicular point, where the new y coordinate
50844            * is the old x coordinate and the new x coordinate is the old y
50845            * coordinate multiplied by -1
50846            * @return {Point} perpendicular point
50847            */
50848           perp: function perp() {
50849             return this.clone()._perp();
50850           },
50851
50852           /**
50853            * Return a version of this point with the x & y coordinates
50854            * rounded to integers.
50855            * @return {Point} rounded point
50856            */
50857           round: function round() {
50858             return this.clone()._round();
50859           },
50860
50861           /**
50862            * Return the magitude of this point: this is the Euclidean
50863            * distance from the 0, 0 coordinate to this point's x and y
50864            * coordinates.
50865            * @return {Number} magnitude
50866            */
50867           mag: function mag() {
50868             return Math.sqrt(this.x * this.x + this.y * this.y);
50869           },
50870
50871           /**
50872            * Judge whether this point is equal to another point, returning
50873            * true or false.
50874            * @param {Point} other the other point
50875            * @return {boolean} whether the points are equal
50876            */
50877           equals: function equals(other) {
50878             return this.x === other.x && this.y === other.y;
50879           },
50880
50881           /**
50882            * Calculate the distance from this point to another point
50883            * @param {Point} p the other point
50884            * @return {Number} distance
50885            */
50886           dist: function dist(p) {
50887             return Math.sqrt(this.distSqr(p));
50888           },
50889
50890           /**
50891            * Calculate the distance from this point to another point,
50892            * without the square root step. Useful if you're comparing
50893            * relative distances.
50894            * @param {Point} p the other point
50895            * @return {Number} distance
50896            */
50897           distSqr: function distSqr(p) {
50898             var dx = p.x - this.x,
50899                 dy = p.y - this.y;
50900             return dx * dx + dy * dy;
50901           },
50902
50903           /**
50904            * Get the angle from the 0, 0 coordinate to this point, in radians
50905            * coordinates.
50906            * @return {Number} angle
50907            */
50908           angle: function angle() {
50909             return Math.atan2(this.y, this.x);
50910           },
50911
50912           /**
50913            * Get the angle from this point to another point, in radians
50914            * @param {Point} b the other point
50915            * @return {Number} angle
50916            */
50917           angleTo: function angleTo(b) {
50918             return Math.atan2(this.y - b.y, this.x - b.x);
50919           },
50920
50921           /**
50922            * Get the angle between this point and another point, in radians
50923            * @param {Point} b the other point
50924            * @return {Number} angle
50925            */
50926           angleWith: function angleWith(b) {
50927             return this.angleWithSep(b.x, b.y);
50928           },
50929
50930           /*
50931            * Find the angle of the two vectors, solving the formula for
50932            * the cross product a x b = |a||b|sin(θ) for θ.
50933            * @param {Number} x the x-coordinate
50934            * @param {Number} y the y-coordinate
50935            * @return {Number} the angle in radians
50936            */
50937           angleWithSep: function angleWithSep(x, y) {
50938             return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
50939           },
50940           _matMult: function _matMult(m) {
50941             var x = m[0] * this.x + m[1] * this.y,
50942                 y = m[2] * this.x + m[3] * this.y;
50943             this.x = x;
50944             this.y = y;
50945             return this;
50946           },
50947           _add: function _add(p) {
50948             this.x += p.x;
50949             this.y += p.y;
50950             return this;
50951           },
50952           _sub: function _sub(p) {
50953             this.x -= p.x;
50954             this.y -= p.y;
50955             return this;
50956           },
50957           _mult: function _mult(k) {
50958             this.x *= k;
50959             this.y *= k;
50960             return this;
50961           },
50962           _div: function _div(k) {
50963             this.x /= k;
50964             this.y /= k;
50965             return this;
50966           },
50967           _multByPoint: function _multByPoint(p) {
50968             this.x *= p.x;
50969             this.y *= p.y;
50970             return this;
50971           },
50972           _divByPoint: function _divByPoint(p) {
50973             this.x /= p.x;
50974             this.y /= p.y;
50975             return this;
50976           },
50977           _unit: function _unit() {
50978             this._div(this.mag());
50979
50980             return this;
50981           },
50982           _perp: function _perp() {
50983             var y = this.y;
50984             this.y = this.x;
50985             this.x = -y;
50986             return this;
50987           },
50988           _rotate: function _rotate(angle) {
50989             var cos = Math.cos(angle),
50990                 sin = Math.sin(angle),
50991                 x = cos * this.x - sin * this.y,
50992                 y = sin * this.x + cos * this.y;
50993             this.x = x;
50994             this.y = y;
50995             return this;
50996           },
50997           _rotateAround: function _rotateAround(angle, p) {
50998             var cos = Math.cos(angle),
50999                 sin = Math.sin(angle),
51000                 x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y),
51001                 y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
51002             this.x = x;
51003             this.y = y;
51004             return this;
51005           },
51006           _round: function _round() {
51007             this.x = Math.round(this.x);
51008             this.y = Math.round(this.y);
51009             return this;
51010           }
51011         };
51012         /**
51013          * Construct a point from an array if necessary, otherwise if the input
51014          * is already a Point, or an unknown type, return it unchanged
51015          * @param {Array<Number>|Point|*} a any kind of input value
51016          * @return {Point} constructed point, or passed-through value.
51017          * @example
51018          * // this
51019          * var point = Point.convert([0, 1]);
51020          * // is equivalent to
51021          * var point = new Point(0, 1);
51022          */
51023
51024         Point.convert = function (a) {
51025           if (a instanceof Point) {
51026             return a;
51027           }
51028
51029           if (Array.isArray(a)) {
51030             return new Point(a[0], a[1]);
51031           }
51032
51033           return a;
51034         };
51035
51036         var vectortilefeature = VectorTileFeature$1;
51037
51038         function VectorTileFeature$1(pbf, end, extent, keys, values) {
51039           // Public
51040           this.properties = {};
51041           this.extent = extent;
51042           this.type = 0; // Private
51043
51044           this._pbf = pbf;
51045           this._geometry = -1;
51046           this._keys = keys;
51047           this._values = values;
51048           pbf.readFields(readFeature, this, end);
51049         }
51050
51051         function readFeature(tag, feature, pbf) {
51052           if (tag == 1) feature.id = pbf.readVarint();else if (tag == 2) readTag(pbf, feature);else if (tag == 3) feature.type = pbf.readVarint();else if (tag == 4) feature._geometry = pbf.pos;
51053         }
51054
51055         function readTag(pbf, feature) {
51056           var end = pbf.readVarint() + pbf.pos;
51057
51058           while (pbf.pos < end) {
51059             var key = feature._keys[pbf.readVarint()],
51060                 value = feature._values[pbf.readVarint()];
51061
51062             feature.properties[key] = value;
51063           }
51064         }
51065
51066         VectorTileFeature$1.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
51067
51068         VectorTileFeature$1.prototype.loadGeometry = function () {
51069           var pbf = this._pbf;
51070           pbf.pos = this._geometry;
51071           var end = pbf.readVarint() + pbf.pos,
51072               cmd = 1,
51073               length = 0,
51074               x = 0,
51075               y = 0,
51076               lines = [],
51077               line;
51078
51079           while (pbf.pos < end) {
51080             if (length <= 0) {
51081               var cmdLen = pbf.readVarint();
51082               cmd = cmdLen & 0x7;
51083               length = cmdLen >> 3;
51084             }
51085
51086             length--;
51087
51088             if (cmd === 1 || cmd === 2) {
51089               x += pbf.readSVarint();
51090               y += pbf.readSVarint();
51091
51092               if (cmd === 1) {
51093                 // moveTo
51094                 if (line) lines.push(line);
51095                 line = [];
51096               }
51097
51098               line.push(new pointGeometry(x, y));
51099             } else if (cmd === 7) {
51100               // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
51101               if (line) {
51102                 line.push(line[0].clone()); // closePolygon
51103               }
51104             } else {
51105               throw new Error('unknown command ' + cmd);
51106             }
51107           }
51108
51109           if (line) lines.push(line);
51110           return lines;
51111         };
51112
51113         VectorTileFeature$1.prototype.bbox = function () {
51114           var pbf = this._pbf;
51115           pbf.pos = this._geometry;
51116           var end = pbf.readVarint() + pbf.pos,
51117               cmd = 1,
51118               length = 0,
51119               x = 0,
51120               y = 0,
51121               x1 = Infinity,
51122               x2 = -Infinity,
51123               y1 = Infinity,
51124               y2 = -Infinity;
51125
51126           while (pbf.pos < end) {
51127             if (length <= 0) {
51128               var cmdLen = pbf.readVarint();
51129               cmd = cmdLen & 0x7;
51130               length = cmdLen >> 3;
51131             }
51132
51133             length--;
51134
51135             if (cmd === 1 || cmd === 2) {
51136               x += pbf.readSVarint();
51137               y += pbf.readSVarint();
51138               if (x < x1) x1 = x;
51139               if (x > x2) x2 = x;
51140               if (y < y1) y1 = y;
51141               if (y > y2) y2 = y;
51142             } else if (cmd !== 7) {
51143               throw new Error('unknown command ' + cmd);
51144             }
51145           }
51146
51147           return [x1, y1, x2, y2];
51148         };
51149
51150         VectorTileFeature$1.prototype.toGeoJSON = function (x, y, z) {
51151           var size = this.extent * Math.pow(2, z),
51152               x0 = this.extent * x,
51153               y0 = this.extent * y,
51154               coords = this.loadGeometry(),
51155               type = VectorTileFeature$1.types[this.type],
51156               i,
51157               j;
51158
51159           function project(line) {
51160             for (var j = 0; j < line.length; j++) {
51161               var p = line[j],
51162                   y2 = 180 - (p.y + y0) * 360 / size;
51163               line[j] = [(p.x + x0) * 360 / size - 180, 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90];
51164             }
51165           }
51166
51167           switch (this.type) {
51168             case 1:
51169               var points = [];
51170
51171               for (i = 0; i < coords.length; i++) {
51172                 points[i] = coords[i][0];
51173               }
51174
51175               coords = points;
51176               project(coords);
51177               break;
51178
51179             case 2:
51180               for (i = 0; i < coords.length; i++) {
51181                 project(coords[i]);
51182               }
51183
51184               break;
51185
51186             case 3:
51187               coords = classifyRings(coords);
51188
51189               for (i = 0; i < coords.length; i++) {
51190                 for (j = 0; j < coords[i].length; j++) {
51191                   project(coords[i][j]);
51192                 }
51193               }
51194
51195               break;
51196           }
51197
51198           if (coords.length === 1) {
51199             coords = coords[0];
51200           } else {
51201             type = 'Multi' + type;
51202           }
51203
51204           var result = {
51205             type: "Feature",
51206             geometry: {
51207               type: type,
51208               coordinates: coords
51209             },
51210             properties: this.properties
51211           };
51212
51213           if ('id' in this) {
51214             result.id = this.id;
51215           }
51216
51217           return result;
51218         }; // classifies an array of rings into polygons with outer rings and holes
51219
51220
51221         function classifyRings(rings) {
51222           var len = rings.length;
51223           if (len <= 1) return [rings];
51224           var polygons = [],
51225               polygon,
51226               ccw;
51227
51228           for (var i = 0; i < len; i++) {
51229             var area = signedArea(rings[i]);
51230             if (area === 0) continue;
51231             if (ccw === undefined) ccw = area < 0;
51232
51233             if (ccw === area < 0) {
51234               if (polygon) polygons.push(polygon);
51235               polygon = [rings[i]];
51236             } else {
51237               polygon.push(rings[i]);
51238             }
51239           }
51240
51241           if (polygon) polygons.push(polygon);
51242           return polygons;
51243         }
51244
51245         function signedArea(ring) {
51246           var sum = 0;
51247
51248           for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
51249             p1 = ring[i];
51250             p2 = ring[j];
51251             sum += (p2.x - p1.x) * (p1.y + p2.y);
51252           }
51253
51254           return sum;
51255         }
51256
51257         var vectortilelayer = VectorTileLayer$1;
51258
51259         function VectorTileLayer$1(pbf, end) {
51260           // Public
51261           this.version = 1;
51262           this.name = null;
51263           this.extent = 4096;
51264           this.length = 0; // Private
51265
51266           this._pbf = pbf;
51267           this._keys = [];
51268           this._values = [];
51269           this._features = [];
51270           pbf.readFields(readLayer, this, end);
51271           this.length = this._features.length;
51272         }
51273
51274         function readLayer(tag, layer, pbf) {
51275           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));
51276         }
51277
51278         function readValueMessage(pbf) {
51279           var value = null,
51280               end = pbf.readVarint() + pbf.pos;
51281
51282           while (pbf.pos < end) {
51283             var tag = pbf.readVarint() >> 3;
51284             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;
51285           }
51286
51287           return value;
51288         } // return feature `i` from this layer as a `VectorTileFeature`
51289
51290
51291         VectorTileLayer$1.prototype.feature = function (i) {
51292           if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
51293           this._pbf.pos = this._features[i];
51294
51295           var end = this._pbf.readVarint() + this._pbf.pos;
51296
51297           return new vectortilefeature(this._pbf, end, this.extent, this._keys, this._values);
51298         };
51299
51300         var vectortile = VectorTile$1;
51301
51302         function VectorTile$1(pbf, end) {
51303           this.layers = pbf.readFields(readTile, {}, end);
51304         }
51305
51306         function readTile(tag, layers, pbf) {
51307           if (tag === 3) {
51308             var layer = new vectortilelayer(pbf, pbf.readVarint() + pbf.pos);
51309             if (layer.length) layers[layer.name] = layer;
51310           }
51311         }
51312
51313         var VectorTile = vectortile;
51314         var VectorTileFeature = vectortilefeature;
51315         var VectorTileLayer = vectortilelayer;
51316         var vectorTile = {
51317           VectorTile: VectorTile,
51318           VectorTileFeature: VectorTileFeature,
51319           VectorTileLayer: VectorTileLayer
51320         };
51321
51322         var accessToken = 'MLY|4100327730013843|5bb78b81720791946a9a7b956c57b7cf';
51323         var apiUrl = 'https://graph.mapillary.com/';
51324         var baseTileUrl = 'https://tiles.mapillary.com/maps/vtp';
51325         var mapFeatureTileUrl = "".concat(baseTileUrl, "/mly_map_feature_point/2/{z}/{x}/{y}?access_token=").concat(accessToken);
51326         var tileUrl = "".concat(baseTileUrl, "/mly1_public/2/{z}/{x}/{y}?access_token=").concat(accessToken);
51327         var trafficSignTileUrl = "".concat(baseTileUrl, "/mly_map_feature_traffic_sign/2/{z}/{x}/{y}?access_token=").concat(accessToken);
51328         var viewercss = 'mapillary-js/mapillary.css';
51329         var viewerjs = 'mapillary-js/mapillary.js';
51330         var minZoom$1 = 14;
51331         var dispatch$4 = dispatch$8('change', 'loadedImages', 'loadedSigns', 'loadedMapFeatures', 'bearingChanged', 'imageChanged');
51332
51333         var _loadViewerPromise$2;
51334
51335         var _mlyActiveImage;
51336
51337         var _mlyCache;
51338
51339         var _mlyFallback = false;
51340
51341         var _mlyHighlightedDetection;
51342
51343         var _mlyShowFeatureDetections = false;
51344         var _mlyShowSignDetections = false;
51345
51346         var _mlyViewer;
51347
51348         var _mlyViewerFilter = ['all']; // Load all data for the specified type from Mapillary vector tiles
51349
51350         function loadTiles$2(which, url, maxZoom, projection) {
51351           var tiler = utilTiler().zoomExtent([minZoom$1, maxZoom]).skipNullIsland(true);
51352           var tiles = tiler.getTiles(projection);
51353           tiles.forEach(function (tile) {
51354             loadTile$1(which, url, tile);
51355           });
51356         } // Load all data for the specified type from one vector tile
51357
51358
51359         function loadTile$1(which, url, tile) {
51360           var cache = _mlyCache.requests;
51361           var tileId = "".concat(tile.id, "-").concat(which);
51362           if (cache.loaded[tileId] || cache.inflight[tileId]) return;
51363           var controller = new AbortController();
51364           cache.inflight[tileId] = controller;
51365           var requestUrl = url.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]).replace('{z}', tile.xyz[2]);
51366           fetch(requestUrl, {
51367             signal: controller.signal
51368           }).then(function (response) {
51369             if (!response.ok) {
51370               throw new Error(response.status + ' ' + response.statusText);
51371             }
51372
51373             cache.loaded[tileId] = true;
51374             delete cache.inflight[tileId];
51375             return response.arrayBuffer();
51376           }).then(function (data) {
51377             if (!data) {
51378               throw new Error('No Data');
51379             }
51380
51381             loadTileDataToCache(data, tile, which);
51382
51383             if (which === 'images') {
51384               dispatch$4.call('loadedImages');
51385             } else if (which === 'signs') {
51386               dispatch$4.call('loadedSigns');
51387             } else if (which === 'points') {
51388               dispatch$4.call('loadedMapFeatures');
51389             }
51390           })["catch"](function () {
51391             cache.loaded[tileId] = true;
51392             delete cache.inflight[tileId];
51393           });
51394         } // Load the data from the vector tile into cache
51395
51396
51397         function loadTileDataToCache(data, tile, which) {
51398           var vectorTile = new VectorTile(new pbf(data));
51399           var features, cache, layer, i, feature, loc, d;
51400
51401           if (vectorTile.layers.hasOwnProperty('image')) {
51402             features = [];
51403             cache = _mlyCache.images;
51404             layer = vectorTile.layers.image;
51405
51406             for (i = 0; i < layer.length; i++) {
51407               feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
51408               loc = feature.geometry.coordinates;
51409               d = {
51410                 loc: loc,
51411                 captured_at: feature.properties.captured_at,
51412                 ca: feature.properties.compass_angle,
51413                 id: feature.properties.id,
51414                 is_pano: feature.properties.is_pano,
51415                 sequence_id: feature.properties.sequence_id
51416               };
51417               cache.forImageId[d.id] = d;
51418               features.push({
51419                 minX: loc[0],
51420                 minY: loc[1],
51421                 maxX: loc[0],
51422                 maxY: loc[1],
51423                 data: d
51424               });
51425             }
51426
51427             if (cache.rtree) {
51428               cache.rtree.load(features);
51429             }
51430           }
51431
51432           if (vectorTile.layers.hasOwnProperty('sequence')) {
51433             features = [];
51434             cache = _mlyCache.sequences;
51435             layer = vectorTile.layers.sequence;
51436
51437             for (i = 0; i < layer.length; i++) {
51438               feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
51439
51440               if (cache.lineString[feature.properties.id]) {
51441                 cache.lineString[feature.properties.id].push(feature);
51442               } else {
51443                 cache.lineString[feature.properties.id] = [feature];
51444               }
51445             }
51446           }
51447
51448           if (vectorTile.layers.hasOwnProperty('point')) {
51449             features = [];
51450             cache = _mlyCache[which];
51451             layer = vectorTile.layers.point;
51452
51453             for (i = 0; i < layer.length; i++) {
51454               feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
51455               loc = feature.geometry.coordinates;
51456               d = {
51457                 loc: loc,
51458                 id: feature.properties.id,
51459                 first_seen_at: feature.properties.first_seen_at,
51460                 last_seen_at: feature.properties.last_seen_at,
51461                 value: feature.properties.value
51462               };
51463               features.push({
51464                 minX: loc[0],
51465                 minY: loc[1],
51466                 maxX: loc[0],
51467                 maxY: loc[1],
51468                 data: d
51469               });
51470             }
51471
51472             if (cache.rtree) {
51473               cache.rtree.load(features);
51474             }
51475           }
51476
51477           if (vectorTile.layers.hasOwnProperty('traffic_sign')) {
51478             features = [];
51479             cache = _mlyCache[which];
51480             layer = vectorTile.layers.traffic_sign;
51481
51482             for (i = 0; i < layer.length; i++) {
51483               feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
51484               loc = feature.geometry.coordinates;
51485               d = {
51486                 loc: loc,
51487                 id: feature.properties.id,
51488                 first_seen_at: feature.properties.first_seen_at,
51489                 last_seen_at: feature.properties.last_seen_at,
51490                 value: feature.properties.value
51491               };
51492               features.push({
51493                 minX: loc[0],
51494                 minY: loc[1],
51495                 maxX: loc[0],
51496                 maxY: loc[1],
51497                 data: d
51498               });
51499             }
51500
51501             if (cache.rtree) {
51502               cache.rtree.load(features);
51503             }
51504           }
51505         } // Get data from the API
51506
51507
51508         function loadData(url) {
51509           return fetch(url).then(function (response) {
51510             if (!response.ok) {
51511               throw new Error(response.status + ' ' + response.statusText);
51512             }
51513
51514             return response.json();
51515           }).then(function (result) {
51516             if (!result) {
51517               return [];
51518             }
51519
51520             return result.data || [];
51521           });
51522         } // Partition viewport into higher zoom tiles
51523
51524
51525         function partitionViewport$2(projection) {
51526           var z = geoScaleToZoom(projection.scale());
51527           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
51528
51529           var tiler = utilTiler().zoomExtent([z2, z2]);
51530           return tiler.getTiles(projection).map(function (tile) {
51531             return tile.extent;
51532           });
51533         } // Return no more than `limit` results per partition.
51534
51535
51536         function searchLimited$2(limit, projection, rtree) {
51537           limit = limit || 5;
51538           return partitionViewport$2(projection).reduce(function (result, extent) {
51539             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
51540               return d.data;
51541             });
51542             return found.length ? result.concat(found) : result;
51543           }, []);
51544         }
51545
51546         var serviceMapillary = {
51547           // Initialize Mapillary
51548           init: function init() {
51549             if (!_mlyCache) {
51550               this.reset();
51551             }
51552
51553             this.event = utilRebind(this, dispatch$4, 'on');
51554           },
51555           // Reset cache and state
51556           reset: function reset() {
51557             if (_mlyCache) {
51558               Object.values(_mlyCache.requests.inflight).forEach(function (request) {
51559                 request.abort();
51560               });
51561             }
51562
51563             _mlyCache = {
51564               images: {
51565                 rtree: new RBush(),
51566                 forImageId: {}
51567               },
51568               image_detections: {
51569                 forImageId: {}
51570               },
51571               signs: {
51572                 rtree: new RBush()
51573               },
51574               points: {
51575                 rtree: new RBush()
51576               },
51577               sequences: {
51578                 rtree: new RBush(),
51579                 lineString: {}
51580               },
51581               requests: {
51582                 loaded: {},
51583                 inflight: {}
51584               }
51585             };
51586             _mlyActiveImage = null;
51587           },
51588           // Get visible images
51589           images: function images(projection) {
51590             var limit = 5;
51591             return searchLimited$2(limit, projection, _mlyCache.images.rtree);
51592           },
51593           // Get visible traffic signs
51594           signs: function signs(projection) {
51595             var limit = 5;
51596             return searchLimited$2(limit, projection, _mlyCache.signs.rtree);
51597           },
51598           // Get visible map (point) features
51599           mapFeatures: function mapFeatures(projection) {
51600             var limit = 5;
51601             return searchLimited$2(limit, projection, _mlyCache.points.rtree);
51602           },
51603           // Get cached image by id
51604           cachedImage: function cachedImage(imageId) {
51605             return _mlyCache.images.forImageId[imageId];
51606           },
51607           // Get visible sequences
51608           sequences: function sequences(projection) {
51609             var viewport = projection.clipExtent();
51610             var min = [viewport[0][0], viewport[1][1]];
51611             var max = [viewport[1][0], viewport[0][1]];
51612             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
51613             var sequenceIds = {};
51614             var lineStrings = [];
51615
51616             _mlyCache.images.rtree.search(bbox).forEach(function (d) {
51617               if (d.data.sequence_id) {
51618                 sequenceIds[d.data.sequence_id] = true;
51619               }
51620             });
51621
51622             Object.keys(sequenceIds).forEach(function (sequenceId) {
51623               if (_mlyCache.sequences.lineString[sequenceId]) {
51624                 lineStrings = lineStrings.concat(_mlyCache.sequences.lineString[sequenceId]);
51625               }
51626             });
51627             return lineStrings;
51628           },
51629           // Load images in the visible area
51630           loadImages: function loadImages(projection) {
51631             loadTiles$2('images', tileUrl, 14, projection);
51632           },
51633           // Load traffic signs in the visible area
51634           loadSigns: function loadSigns(projection) {
51635             loadTiles$2('signs', trafficSignTileUrl, 14, projection);
51636           },
51637           // Load map (point) features in the visible area
51638           loadMapFeatures: function loadMapFeatures(projection) {
51639             loadTiles$2('points', mapFeatureTileUrl, 14, projection);
51640           },
51641           // Return a promise that resolves when the image viewer (Mapillary JS) library has finished loading
51642           ensureViewerLoaded: function ensureViewerLoaded(context) {
51643             if (_loadViewerPromise$2) return _loadViewerPromise$2; // add mly-wrapper
51644
51645             var wrap = context.container().select('.photoviewer').selectAll('.mly-wrapper').data([0]);
51646             wrap.enter().append('div').attr('id', 'ideditor-mly').attr('class', 'photo-wrapper mly-wrapper').classed('hide', true);
51647             var that = this;
51648             _loadViewerPromise$2 = new Promise(function (resolve, reject) {
51649               var loadedCount = 0;
51650
51651               function loaded() {
51652                 loadedCount += 1; // wait until both files are loaded
51653
51654                 if (loadedCount === 2) resolve();
51655               }
51656
51657               var head = select('head'); // load mapillary-viewercss
51658
51659               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 () {
51660                 reject();
51661               }); // load mapillary-viewerjs
51662
51663               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 () {
51664                 reject();
51665               });
51666             })["catch"](function () {
51667               _loadViewerPromise$2 = null;
51668             }).then(function () {
51669               that.initViewer(context);
51670             });
51671             return _loadViewerPromise$2;
51672           },
51673           // Load traffic sign image sprites
51674           loadSignResources: function loadSignResources(context) {
51675             context.ui().svgDefs.addSprites(['mapillary-sprite'], false
51676             /* don't override colors */
51677             );
51678             return this;
51679           },
51680           // Load map (point) feature image sprites
51681           loadObjectResources: function loadObjectResources(context) {
51682             context.ui().svgDefs.addSprites(['mapillary-object-sprite'], false
51683             /* don't override colors */
51684             );
51685             return this;
51686           },
51687           // Remove previous detections in image viewer
51688           resetTags: function resetTags() {
51689             if (_mlyViewer && !_mlyFallback) {
51690               _mlyViewer.getComponent('tag').removeAll();
51691             }
51692           },
51693           // Show map feature detections in image viewer
51694           showFeatureDetections: function showFeatureDetections(value) {
51695             _mlyShowFeatureDetections = value;
51696
51697             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
51698               this.resetTags();
51699             }
51700           },
51701           // Show traffic sign detections in image viewer
51702           showSignDetections: function showSignDetections(value) {
51703             _mlyShowSignDetections = value;
51704
51705             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
51706               this.resetTags();
51707             }
51708           },
51709           // Apply filter to image viewer
51710           filterViewer: function filterViewer(context) {
51711             var showsPano = context.photos().showsPanoramic();
51712             var showsFlat = context.photos().showsFlat();
51713             var fromDate = context.photos().fromDate();
51714             var toDate = context.photos().toDate();
51715             var filter = ['all'];
51716             if (!showsPano) filter.push(['!=', 'cameraType', 'spherical']);
51717             if (!showsFlat && showsPano) filter.push(['==', 'pano', true]);
51718
51719             if (fromDate) {
51720               filter.push(['>=', 'capturedAt', new Date(fromDate).getTime()]);
51721             }
51722
51723             if (toDate) {
51724               filter.push(['>=', 'capturedAt', new Date(toDate).getTime()]);
51725             }
51726
51727             if (_mlyViewer) {
51728               _mlyViewer.setFilter(filter);
51729             }
51730
51731             _mlyViewerFilter = filter;
51732             return filter;
51733           },
51734           // Make the image viewer visible
51735           showViewer: function showViewer(context) {
51736             var wrap = context.container().select('.photoviewer').classed('hide', false);
51737             var isHidden = wrap.selectAll('.photo-wrapper.mly-wrapper.hide').size();
51738
51739             if (isHidden && _mlyViewer) {
51740               wrap.selectAll('.photo-wrapper:not(.mly-wrapper)').classed('hide', true);
51741               wrap.selectAll('.photo-wrapper.mly-wrapper').classed('hide', false);
51742
51743               _mlyViewer.resize();
51744             }
51745
51746             return this;
51747           },
51748           // Hide the image viewer and resets map markers
51749           hideViewer: function hideViewer(context) {
51750             _mlyActiveImage = null;
51751
51752             if (!_mlyFallback && _mlyViewer) {
51753               _mlyViewer.getComponent('sequence').stop();
51754             }
51755
51756             var viewer = context.container().select('.photoviewer');
51757             if (!viewer.empty()) viewer.datum(null);
51758             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
51759             this.updateUrlImage(null);
51760             dispatch$4.call('imageChanged');
51761             dispatch$4.call('loadedMapFeatures');
51762             dispatch$4.call('loadedSigns');
51763             return this.setStyles(context, null);
51764           },
51765           // Update the URL with current image id
51766           updateUrlImage: function updateUrlImage(imageId) {
51767             if (!window.mocha) {
51768               var hash = utilStringQs(window.location.hash);
51769
51770               if (imageId) {
51771                 hash.photo = 'mapillary/' + imageId;
51772               } else {
51773                 delete hash.photo;
51774               }
51775
51776               window.location.replace('#' + utilQsString(hash, true));
51777             }
51778           },
51779           // Highlight the detection in the viewer that is related to the clicked map feature
51780           highlightDetection: function highlightDetection(detection) {
51781             if (detection) {
51782               _mlyHighlightedDetection = detection.id;
51783             }
51784
51785             return this;
51786           },
51787           // Initialize image viewer (Mapillar JS)
51788           initViewer: function initViewer(context) {
51789             var that = this;
51790             if (!window.mapillary) return;
51791             var opts = {
51792               accessToken: accessToken,
51793               component: {
51794                 cover: false,
51795                 keyboard: false,
51796                 tag: true
51797               },
51798               container: 'ideditor-mly'
51799             }; // Disable components requiring WebGL support
51800
51801             if (!mapillary.isSupported() && mapillary.isFallbackSupported()) {
51802               _mlyFallback = true;
51803               opts.component = {
51804                 cover: false,
51805                 direction: false,
51806                 imagePlane: false,
51807                 keyboard: false,
51808                 mouse: false,
51809                 sequence: false,
51810                 tag: false,
51811                 image: true,
51812                 // fallback
51813                 navigation: true // fallback
51814
51815               };
51816             }
51817
51818             _mlyViewer = new mapillary.Viewer(opts);
51819
51820             _mlyViewer.on('image', imageChanged);
51821
51822             _mlyViewer.on('bearing', bearingChanged);
51823
51824             if (_mlyViewerFilter) {
51825               _mlyViewer.setFilter(_mlyViewerFilter);
51826             } // Register viewer resize handler
51827
51828
51829             context.ui().photoviewer.on('resize.mapillary', function () {
51830               if (_mlyViewer) _mlyViewer.resize();
51831             }); // imageChanged: called after the viewer has changed images and is ready.
51832
51833             function imageChanged(node) {
51834               that.resetTags();
51835               var image = node.image;
51836               that.setActiveImage(image);
51837               that.setStyles(context, null);
51838               var loc = [image.originalLngLat.lng, image.originalLngLat.lat];
51839               context.map().centerEase(loc);
51840               that.updateUrlImage(image.id);
51841
51842               if (_mlyShowFeatureDetections || _mlyShowSignDetections) {
51843                 that.updateDetections(image.id, "".concat(apiUrl, "/").concat(image.id, "/detections?access_token=").concat(accessToken, "&fields=id,image,geometry,value"));
51844               }
51845
51846               dispatch$4.call('imageChanged');
51847             } // bearingChanged: called when the bearing changes in the image viewer.
51848
51849
51850             function bearingChanged(e) {
51851               dispatch$4.call('bearingChanged', undefined, e);
51852             }
51853           },
51854           // Move to an image
51855           selectImage: function selectImage(context, imageId) {
51856             if (_mlyViewer && imageId) {
51857               _mlyViewer.moveTo(imageId)["catch"](function (e) {
51858                 console.error('mly3', e); // eslint-disable-line no-console
51859               });
51860             }
51861
51862             return this;
51863           },
51864           // Return the currently displayed image
51865           getActiveImage: function getActiveImage() {
51866             return _mlyActiveImage;
51867           },
51868           // Return a list of detection objects for the given id
51869           getDetections: function getDetections(id) {
51870             return loadData("".concat(apiUrl, "/").concat(id, "/detections?access_token=").concat(accessToken, "&fields=id,value,image"));
51871           },
51872           // Set the currently visible image
51873           setActiveImage: function setActiveImage(image) {
51874             if (image) {
51875               _mlyActiveImage = {
51876                 ca: image.originalCompassAngle,
51877                 id: image.id,
51878                 loc: [image.originalLngLat.lng, image.originalLngLat.lat],
51879                 is_pano: image.cameraType === 'spherical',
51880                 sequence_id: image.sequenceId
51881               };
51882             } else {
51883               _mlyActiveImage = null;
51884             }
51885           },
51886           // Update the currently highlighted sequence and selected bubble.
51887           setStyles: function setStyles(context, hovered) {
51888             var hoveredImageId = hovered && hovered.id;
51889             var hoveredSequenceId = hovered && hovered.sequence_id;
51890             var selectedSequenceId = _mlyActiveImage && _mlyActiveImage.sequence_id;
51891             context.container().selectAll('.layer-mapillary .viewfield-group').classed('highlighted', function (d) {
51892               return d.sequence_id === selectedSequenceId || d.id === hoveredImageId;
51893             }).classed('hovered', function (d) {
51894               return d.id === hoveredImageId;
51895             });
51896             context.container().selectAll('.layer-mapillary .sequence').classed('highlighted', function (d) {
51897               return d.properties.id === hoveredSequenceId;
51898             }).classed('currentView', function (d) {
51899               return d.properties.id === selectedSequenceId;
51900             });
51901             return this;
51902           },
51903           // Get detections for the current image and shows them in the image viewer
51904           updateDetections: function updateDetections(imageId, url) {
51905             if (!_mlyViewer || _mlyFallback) return;
51906             if (!imageId) return;
51907             var cache = _mlyCache.image_detections;
51908
51909             if (cache.forImageId[imageId]) {
51910               showDetections(_mlyCache.image_detections.forImageId[imageId]);
51911             } else {
51912               loadData(url).then(function (detections) {
51913                 detections.forEach(function (detection) {
51914                   if (!cache.forImageId[imageId]) {
51915                     cache.forImageId[imageId] = [];
51916                   }
51917
51918                   cache.forImageId[imageId].push({
51919                     geometry: detection.geometry,
51920                     id: detection.id,
51921                     image_id: imageId,
51922                     value: detection.value
51923                   });
51924                 });
51925                 showDetections(_mlyCache.image_detections.forImageId[imageId] || []);
51926               });
51927             } // Create a tag for each detection and shows it in the image viewer
51928
51929
51930             function showDetections(detections) {
51931               var tagComponent = _mlyViewer.getComponent('tag');
51932
51933               detections.forEach(function (data) {
51934                 var tag = makeTag(data);
51935
51936                 if (tag) {
51937                   tagComponent.add([tag]);
51938                 }
51939               });
51940             } // Create a Mapillary JS tag object
51941
51942
51943             function makeTag(data) {
51944               var valueParts = data.value.split('--');
51945               if (!valueParts.length) return;
51946               var tag;
51947               var text;
51948               var color = 0xffffff;
51949
51950               if (_mlyHighlightedDetection === data.id) {
51951                 color = 0xffff00;
51952                 text = valueParts[1];
51953
51954                 if (text === 'flat' || text === 'discrete' || text === 'sign') {
51955                   text = valueParts[2];
51956                 }
51957
51958                 text = text.replace(/-/g, ' ');
51959                 text = text.charAt(0).toUpperCase() + text.slice(1);
51960                 _mlyHighlightedDetection = null;
51961               }
51962
51963               var decodedGeometry = window.atob(data.geometry);
51964               var uintArray = new Uint8Array(decodedGeometry.length);
51965
51966               for (var i = 0; i < decodedGeometry.length; i++) {
51967                 uintArray[i] = decodedGeometry.charCodeAt(i);
51968               }
51969
51970               var tile = new VectorTile(new pbf(uintArray.buffer));
51971               var layer = tile.layers['mpy-or'];
51972               var geometries = layer.feature(0).loadGeometry();
51973               var polygon = geometries.map(function (ring) {
51974                 return ring.map(function (point) {
51975                   return [point.x / layer.extent, point.y / layer.extent];
51976                 });
51977               });
51978               tag = new mapillary.OutlineTag(data.id, new mapillary.PolygonGeometry(polygon[0]), {
51979                 text: text,
51980                 textColor: color,
51981                 lineColor: color,
51982                 lineWidth: 2,
51983                 fillColor: color,
51984                 fillOpacity: 0.3
51985               });
51986               return tag;
51987             }
51988           },
51989           // Return the current cache
51990           cache: function cache() {
51991             return _mlyCache;
51992           }
51993         };
51994
51995         function validationIssue(attrs) {
51996           this.type = attrs.type; // required - name of rule that created the issue (e.g. 'missing_tag')
51997
51998           this.subtype = attrs.subtype; // optional - category of the issue within the type (e.g. 'relation_type' under 'missing_tag')
51999
52000           this.severity = attrs.severity; // required - 'warning' or 'error'
52001
52002           this.message = attrs.message; // required - function returning localized string
52003
52004           this.reference = attrs.reference; // optional - function(selection) to render reference information
52005
52006           this.entityIds = attrs.entityIds; // optional - array of IDs of entities involved in the issue
52007
52008           this.loc = attrs.loc; // optional - [lon, lat] to zoom in on to see the issue
52009
52010           this.data = attrs.data; // optional - object containing extra data for the fixes
52011
52012           this.dynamicFixes = attrs.dynamicFixes; // optional - function(context) returning fixes
52013
52014           this.hash = attrs.hash; // optional - string to further differentiate the issue
52015
52016           this.id = generateID.apply(this); // generated - see below
52017
52018           this.autoFix = null; // generated - if autofix exists, will be set below
52019           // A unique, deterministic string hash.
52020           // Issues with identical id values are considered identical.
52021
52022           function generateID() {
52023             var parts = [this.type];
52024
52025             if (this.hash) {
52026               // subclasses can pass in their own differentiator
52027               parts.push(this.hash);
52028             }
52029
52030             if (this.subtype) {
52031               parts.push(this.subtype);
52032             } // include the entities this issue is for
52033             // (sort them so the id is deterministic)
52034
52035
52036             if (this.entityIds) {
52037               var entityKeys = this.entityIds.slice().sort();
52038               parts.push.apply(parts, entityKeys);
52039             }
52040
52041             return parts.join(':');
52042           }
52043
52044           this.extent = function (resolver) {
52045             if (this.loc) {
52046               return geoExtent(this.loc);
52047             }
52048
52049             if (this.entityIds && this.entityIds.length) {
52050               return this.entityIds.reduce(function (extent, entityId) {
52051                 return extent.extend(resolver.entity(entityId).extent(resolver));
52052               }, geoExtent());
52053             }
52054
52055             return null;
52056           };
52057
52058           this.fixes = function (context) {
52059             var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
52060             var issue = this;
52061
52062             if (issue.severity === 'warning') {
52063               // allow ignoring any issue that's not an error
52064               fixes.push(new validationIssueFix({
52065                 title: _t.html('issues.fix.ignore_issue.title'),
52066                 icon: 'iD-icon-close',
52067                 onClick: function onClick() {
52068                   context.validator().ignoreIssue(this.issue.id);
52069                 }
52070               }));
52071             }
52072
52073             fixes.forEach(function (fix) {
52074               // the id doesn't matter as long as it's unique to this issue/fix
52075               fix.id = fix.title; // add a reference to the issue for use in actions
52076
52077               fix.issue = issue;
52078
52079               if (fix.autoArgs) {
52080                 issue.autoFix = fix;
52081               }
52082             });
52083             return fixes;
52084           };
52085         }
52086         function validationIssueFix(attrs) {
52087           this.title = attrs.title; // Required
52088
52089           this.onClick = attrs.onClick; // Optional - the function to run to apply the fix
52090
52091           this.disabledReason = attrs.disabledReason; // Optional - a string explaining why the fix is unavailable, if any
52092
52093           this.icon = attrs.icon; // Optional - shows 'iD-icon-wrench' if not set
52094
52095           this.entityIds = attrs.entityIds || []; // Optional - used for hover-higlighting.
52096
52097           this.autoArgs = attrs.autoArgs; // Optional - pass [actions, annotation] arglist if this fix can automatically run
52098
52099           this.issue = null; // Generated link - added by validationIssue
52100         }
52101
52102         var buildRuleChecks = function buildRuleChecks() {
52103           return {
52104             equals: function equals(_equals) {
52105               return function (tags) {
52106                 return Object.keys(_equals).every(function (k) {
52107                   return _equals[k] === tags[k];
52108                 });
52109               };
52110             },
52111             notEquals: function notEquals(_notEquals) {
52112               return function (tags) {
52113                 return Object.keys(_notEquals).some(function (k) {
52114                   return _notEquals[k] !== tags[k];
52115                 });
52116               };
52117             },
52118             absence: function absence(_absence) {
52119               return function (tags) {
52120                 return Object.keys(tags).indexOf(_absence) === -1;
52121               };
52122             },
52123             presence: function presence(_presence) {
52124               return function (tags) {
52125                 return Object.keys(tags).indexOf(_presence) > -1;
52126               };
52127             },
52128             greaterThan: function greaterThan(_greaterThan) {
52129               var key = Object.keys(_greaterThan)[0];
52130               var value = _greaterThan[key];
52131               return function (tags) {
52132                 return tags[key] > value;
52133               };
52134             },
52135             greaterThanEqual: function greaterThanEqual(_greaterThanEqual) {
52136               var key = Object.keys(_greaterThanEqual)[0];
52137               var value = _greaterThanEqual[key];
52138               return function (tags) {
52139                 return tags[key] >= value;
52140               };
52141             },
52142             lessThan: function lessThan(_lessThan) {
52143               var key = Object.keys(_lessThan)[0];
52144               var value = _lessThan[key];
52145               return function (tags) {
52146                 return tags[key] < value;
52147               };
52148             },
52149             lessThanEqual: function lessThanEqual(_lessThanEqual) {
52150               var key = Object.keys(_lessThanEqual)[0];
52151               var value = _lessThanEqual[key];
52152               return function (tags) {
52153                 return tags[key] <= value;
52154               };
52155             },
52156             positiveRegex: function positiveRegex(_positiveRegex) {
52157               var tagKey = Object.keys(_positiveRegex)[0];
52158
52159               var expression = _positiveRegex[tagKey].join('|');
52160
52161               var regex = new RegExp(expression);
52162               return function (tags) {
52163                 return regex.test(tags[tagKey]);
52164               };
52165             },
52166             negativeRegex: function negativeRegex(_negativeRegex) {
52167               var tagKey = Object.keys(_negativeRegex)[0];
52168
52169               var expression = _negativeRegex[tagKey].join('|');
52170
52171               var regex = new RegExp(expression);
52172               return function (tags) {
52173                 return !regex.test(tags[tagKey]);
52174               };
52175             }
52176           };
52177         };
52178
52179         var buildLineKeys = function buildLineKeys() {
52180           return {
52181             highway: {
52182               rest_area: true,
52183               services: true
52184             },
52185             railway: {
52186               roundhouse: true,
52187               station: true,
52188               traverser: true,
52189               turntable: true,
52190               wash: true
52191             }
52192           };
52193         };
52194
52195         var serviceMapRules = {
52196           init: function init() {
52197             this._ruleChecks = buildRuleChecks();
52198             this._validationRules = [];
52199             this._areaKeys = osmAreaKeys;
52200             this._lineKeys = buildLineKeys();
52201           },
52202           // list of rules only relevant to tag checks...
52203           filterRuleChecks: function filterRuleChecks(selector) {
52204             var _ruleChecks = this._ruleChecks;
52205             return Object.keys(selector).reduce(function (rules, key) {
52206               if (['geometry', 'error', 'warning'].indexOf(key) === -1) {
52207                 rules.push(_ruleChecks[key](selector[key]));
52208               }
52209
52210               return rules;
52211             }, []);
52212           },
52213           // builds tagMap from mapcss-parse selector object...
52214           buildTagMap: function buildTagMap(selector) {
52215             var getRegexValues = function getRegexValues(regexes) {
52216               return regexes.map(function (regex) {
52217                 return regex.replace(/\$|\^/g, '');
52218               });
52219             };
52220
52221             var tagMap = Object.keys(selector).reduce(function (expectedTags, key) {
52222               var values;
52223               var isRegex = /regex/gi.test(key);
52224               var isEqual = /equals/gi.test(key);
52225
52226               if (isRegex || isEqual) {
52227                 Object.keys(selector[key]).forEach(function (selectorKey) {
52228                   values = isEqual ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
52229
52230                   if (expectedTags.hasOwnProperty(selectorKey)) {
52231                     values = values.concat(expectedTags[selectorKey]);
52232                   }
52233
52234                   expectedTags[selectorKey] = values;
52235                 });
52236               } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
52237                 var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
52238                 values = [selector[key][tagKey]];
52239
52240                 if (expectedTags.hasOwnProperty(tagKey)) {
52241                   values = values.concat(expectedTags[tagKey]);
52242                 }
52243
52244                 expectedTags[tagKey] = values;
52245               }
52246
52247               return expectedTags;
52248             }, {});
52249             return tagMap;
52250           },
52251           // inspired by osmWay#isArea()
52252           inferGeometry: function inferGeometry(tagMap) {
52253             var _lineKeys = this._lineKeys;
52254             var _areaKeys = this._areaKeys;
52255
52256             var keyValueDoesNotImplyArea = function keyValueDoesNotImplyArea(key) {
52257               return utilArrayIntersection(tagMap[key], Object.keys(_areaKeys[key])).length > 0;
52258             };
52259
52260             var keyValueImpliesLine = function keyValueImpliesLine(key) {
52261               return utilArrayIntersection(tagMap[key], Object.keys(_lineKeys[key])).length > 0;
52262             };
52263
52264             if (tagMap.hasOwnProperty('area')) {
52265               if (tagMap.area.indexOf('yes') > -1) {
52266                 return 'area';
52267               }
52268
52269               if (tagMap.area.indexOf('no') > -1) {
52270                 return 'line';
52271               }
52272             }
52273
52274             for (var key in tagMap) {
52275               if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
52276                 return 'area';
52277               }
52278
52279               if (key in _lineKeys && keyValueImpliesLine(key)) {
52280                 return 'area';
52281               }
52282             }
52283
52284             return 'line';
52285           },
52286           // adds from mapcss-parse selector check...
52287           addRule: function addRule(selector) {
52288             var rule = {
52289               // checks relevant to mapcss-selector
52290               checks: this.filterRuleChecks(selector),
52291               // true if all conditions for a tag error are true..
52292               matches: function matches(entity) {
52293                 return this.checks.every(function (check) {
52294                   return check(entity.tags);
52295                 });
52296               },
52297               // borrowed from Way#isArea()
52298               inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
52299               geometryMatches: function geometryMatches(entity, graph) {
52300                 if (entity.type === 'node' || entity.type === 'relation') {
52301                   return selector.geometry === entity.type;
52302                 } else if (entity.type === 'way') {
52303                   return this.inferredGeometry === entity.geometry(graph);
52304                 }
52305               },
52306               // when geometries match and tag matches are present, return a warning...
52307               findIssues: function findIssues(entity, graph, issues) {
52308                 if (this.geometryMatches(entity, graph) && this.matches(entity)) {
52309                   var severity = Object.keys(selector).indexOf('error') > -1 ? 'error' : 'warning';
52310                   var _message = selector[severity];
52311                   issues.push(new validationIssue({
52312                     type: 'maprules',
52313                     severity: severity,
52314                     message: function message() {
52315                       return _message;
52316                     },
52317                     entityIds: [entity.id]
52318                   }));
52319                 }
52320               }
52321             };
52322
52323             this._validationRules.push(rule);
52324           },
52325           clearRules: function clearRules() {
52326             this._validationRules = [];
52327           },
52328           // returns validationRules...
52329           validationRules: function validationRules() {
52330             return this._validationRules;
52331           },
52332           // returns ruleChecks
52333           ruleChecks: function ruleChecks() {
52334             return this._ruleChecks;
52335           }
52336         };
52337
52338         var apibase$2 = 'https://nominatim.openstreetmap.org/';
52339         var _inflight$2 = {};
52340
52341         var _nominatimCache;
52342
52343         var serviceNominatim = {
52344           init: function init() {
52345             _inflight$2 = {};
52346             _nominatimCache = new RBush();
52347           },
52348           reset: function reset() {
52349             Object.values(_inflight$2).forEach(function (controller) {
52350               controller.abort();
52351             });
52352             _inflight$2 = {};
52353             _nominatimCache = new RBush();
52354           },
52355           countryCode: function countryCode(location, callback) {
52356             this.reverse(location, function (err, result) {
52357               if (err) {
52358                 return callback(err);
52359               } else if (result.address) {
52360                 return callback(null, result.address.country_code);
52361               } else {
52362                 return callback('Unable to geocode', null);
52363               }
52364             });
52365           },
52366           reverse: function reverse(loc, callback) {
52367             var cached = _nominatimCache.search({
52368               minX: loc[0],
52369               minY: loc[1],
52370               maxX: loc[0],
52371               maxY: loc[1]
52372             });
52373
52374             if (cached.length > 0) {
52375               if (callback) callback(null, cached[0].data);
52376               return;
52377             }
52378
52379             var params = {
52380               zoom: 13,
52381               format: 'json',
52382               addressdetails: 1,
52383               lat: loc[1],
52384               lon: loc[0]
52385             };
52386             var url = apibase$2 + 'reverse?' + utilQsString(params);
52387             if (_inflight$2[url]) return;
52388             var controller = new AbortController();
52389             _inflight$2[url] = controller;
52390             d3_json(url, {
52391               signal: controller.signal
52392             }).then(function (result) {
52393               delete _inflight$2[url];
52394
52395               if (result && result.error) {
52396                 throw new Error(result.error);
52397               }
52398
52399               var extent = geoExtent(loc).padByMeters(200);
52400
52401               _nominatimCache.insert(Object.assign(extent.bbox(), {
52402                 data: result
52403               }));
52404
52405               if (callback) callback(null, result);
52406             })["catch"](function (err) {
52407               delete _inflight$2[url];
52408               if (err.name === 'AbortError') return;
52409               if (callback) callback(err.message);
52410             });
52411           },
52412           search: function search(val, callback) {
52413             var searchVal = encodeURIComponent(val);
52414             var url = apibase$2 + 'search/' + searchVal + '?limit=10&format=json';
52415             if (_inflight$2[url]) return;
52416             var controller = new AbortController();
52417             _inflight$2[url] = controller;
52418             d3_json(url, {
52419               signal: controller.signal
52420             }).then(function (result) {
52421               delete _inflight$2[url];
52422
52423               if (result && result.error) {
52424                 throw new Error(result.error);
52425               }
52426
52427               if (callback) callback(null, result);
52428             })["catch"](function (err) {
52429               delete _inflight$2[url];
52430               if (err.name === 'AbortError') return;
52431               if (callback) callback(err.message);
52432             });
52433           }
52434         };
52435
52436         // for punction see https://stackoverflow.com/a/21224179
52437
52438         function simplify$1(str) {
52439           if (typeof str !== 'string') return '';
52440           return diacritics.remove(str.replace(/&/g, 'and').replace(/İ/ig, 'i') // for BİM, İşbank - #5017
52441           .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());
52442         }
52443
52444         var matchGroups$1 = {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/wine"],camping:["leisure/park","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/dialysis"],confectionery:["shop/candy","shop/chocolate","shop/confectionery"],convenience:["shop/beauty","shop/chemist","shop/convenience","shop/cosmetics","shop/grocery","shop/newsagent"],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/mobile","shop/mobile_phone","shop/telecommunication"],fabric:["shop/fabric","shop/haberdashery","shop/sewing"],fashion:["shop/accessories","shop/bag","shop/botique","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/pub","amenity/bar","amenity/cafe","amenity/fast_food","amenity/ice_cream","amenity/restaurant","shop/bakery","shop/ice_cream","shop/pastry","shop/tea","shop/coffee"],fuel:["amenity/fuel","shop/gas","shop/convenience;gas","shop/gas;convenience"],gift:["shop/gift","shop/card","shop/cards","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/outdoor","shop/sports"],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/rental"],school:["amenity/childcare","amenity/college","amenity/kindergarten","amenity/language_school","amenity/prep_school","amenity/school","amenity/university"],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/vending_machine"],storage:["shop/storage_units","shop/storage_rental"],weight_loss:["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"]};
52445         var matchGroupsJSON = {
52446         matchGroups: matchGroups$1
52447         };
52448
52449         var 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 árbol|fountain|golf|government|graveyard)$","^(hofladen|librairie|magazine?|maison)$","^(mobile home|skate)?\\s?park$","^(n\\s?\\/?\\s?a|name|no\\s?name|none|null|temporary|test|unknown)$","^(obuwie|pond|pool|sale|shops?|sklep|stores?)$","^\\?+$","^tattoo( studio)?$","^windmill$","^церковная( лавка)?$"];
52450         var genericWordsJSON = {
52451         genericWords: genericWords
52452         };
52453
52454         var trees$1 = {brands:{emoji:"🍔",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:"🚩",mainTag:"flag:wikidata",nameTags:{primary:"^(flag:name|flag:name:\\w+)$",alternate:"^(country|country:\\w+|flag|flag:\\w+|subject|subject:\\w+)$"}},operators:{emoji:"💼",mainTag:"operator:wikidata",sourceTags:["operator"],nameTags:{primary:"^(name|name:\\w+|operator|operator:\\w+)$",alternate:"^(brand|brand:\\w+|\\w+_name|\\w+_name:\\w+)$"}},transit:{emoji:"🚇",mainTag:"network:wikidata",sourceTags:["network"],nameTags:{primary:"^network$",alternate:"^(operator|operator:\\w+|network:\\w+|\\w+_name|\\w+_name:\\w+)$"}}};
52455         var treesJSON = {
52456         trees: trees$1
52457         };
52458
52459         var matchGroups = matchGroupsJSON.matchGroups;
52460         var trees = treesJSON.trees;
52461         var Matcher = /*#__PURE__*/function () {
52462           //
52463           // `constructor`
52464           // initialize the genericWords regexes
52465           function Matcher() {
52466             var _this = this;
52467
52468             _classCallCheck$1(this, Matcher);
52469
52470             // The `matchIndex` is a specialized structure that allows us to quickly answer
52471             //   _"Given a [key/value tagpair, name, location], what canonical items (brands etc) can match it?"_
52472             //
52473             // The index contains all valid combinations of k/v tagpairs and names
52474             // matchIndex:
52475             // {
52476             //   'k/v': {
52477             //     'primary':         Map (String 'nsimple' -> Set (itemIDs…),   // matches for tags like `name`, `name:xx`, etc.
52478             //     'alternate':       Map (String 'nsimple' -> Set (itemIDs…),   // matches for tags like `alt_name`, `brand`, etc.
52479             //     'excludeNamed':    Map (String 'pattern' -> RegExp),
52480             //     'excludeGeneric':  Map (String 'pattern' -> RegExp)
52481             //   },
52482             // }
52483             //
52484             // {
52485             //   'amenity/bank': {
52486             //     'primary': {
52487             //       'firstbank':              Set ("firstbank-978cca", "firstbank-9794e6", "firstbank-f17495", …),
52488             //       …
52489             //     },
52490             //     'alternate': {
52491             //       '1stbank':                Set ("firstbank-f17495"),
52492             //       …
52493             //     }
52494             //   },
52495             //   'shop/supermarket': {
52496             //     'primary': {
52497             //       'coop':                   Set ("coop-76454b", "coop-ebf2d9", "coop-36e991", …),
52498             //       'coopfood':               Set ("coopfood-a8278b", …),
52499             //       …
52500             //     },
52501             //     'alternate': {
52502             //       'coop':                   Set ("coopfood-a8278b", …),
52503             //       'federatedcooperatives':  Set ("coop-76454b", …),
52504             //       'thecooperative':         Set ("coopfood-a8278b", …),
52505             //       …
52506             //     }
52507             //   }
52508             // }
52509             //
52510             this.matchIndex = undefined; // The `genericWords` structure matches the contents of genericWords.json to instantiated RegExp objects
52511             // Map (String 'pattern' -> RegExp),
52512
52513             this.genericWords = new Map();
52514             (genericWordsJSON.genericWords || []).forEach(function (s) {
52515               return _this.genericWords.set(s, new RegExp(s, 'i'));
52516             }); // The `itemLocation` structure maps itemIDs to locationSetIDs:
52517             // {
52518             //   'firstbank-f17495':  '+[first_bank_western_us.geojson]',
52519             //   'firstbank-978cca':  '+[first_bank_carolinas.geojson]',
52520             //   'coop-76454b':       '+[Q16]',
52521             //   'coopfood-a8278b':   '+[Q23666]',
52522             //   …
52523             // }
52524
52525             this.itemLocation = undefined; // The `locationSets` structure maps locationSetIDs to *resolved* locationSets:
52526             // {
52527             //   '+[first_bank_western_us.geojson]':  GeoJSON {…},
52528             //   '+[first_bank_carolinas.geojson]':   GeoJSON {…},
52529             //   '+[Q16]':                            GeoJSON {…},
52530             //   '+[Q23666]':                         GeoJSON {…},
52531             //   …
52532             // }
52533
52534             this.locationSets = undefined; // The `locationIndex` is an instance of which-polygon spatial index for the locationSets.
52535
52536             this.locationIndex = undefined; // Array of match conflict pairs (currently unused)
52537
52538             this.warnings = [];
52539           } //
52540           // `buildMatchIndex()`
52541           // Call this to prepare the matcher for use
52542           //
52543           // `data` needs to be an Object indexed on a 'tree/key/value' path.
52544           // (e.g. cache filled by `fileTree.read` or data found in `dist/nsi.json`)
52545           // {
52546           //    'brands/amenity/bank': { properties: {}, items: [ {}, {}, … ] },
52547           //    'brands/amenity/bar':  { properties: {}, items: [ {}, {}, … ] },
52548           //    …
52549           // }
52550           //
52551
52552
52553           _createClass$1(Matcher, [{
52554             key: "buildMatchIndex",
52555             value: function buildMatchIndex(data) {
52556               var that = this;
52557               if (that.matchIndex) return; // it was built already
52558
52559               that.matchIndex = new Map();
52560               Object.keys(data).forEach(function (tkv) {
52561                 var category = data[tkv];
52562                 var parts = tkv.split('/', 3); // tkv = "tree/key/value"
52563
52564                 var t = parts[0];
52565                 var k = parts[1];
52566                 var v = parts[2];
52567                 var thiskv = "".concat(k, "/").concat(v);
52568                 var tree = trees[t];
52569                 var branch = that.matchIndex.get(thiskv);
52570
52571                 if (!branch) {
52572                   branch = {
52573                     primary: new Map(),
52574                     alternate: new Map(),
52575                     excludeGeneric: new Map(),
52576                     excludeNamed: new Map()
52577                   };
52578                   that.matchIndex.set(thiskv, branch);
52579                 } // ADD EXCLUSIONS
52580
52581
52582                 var properties = category.properties || {};
52583                 var exclude = properties.exclude || {};
52584                 (exclude.generic || []).forEach(function (s) {
52585                   return branch.excludeGeneric.set(s, new RegExp(s, 'i'));
52586                 });
52587                 (exclude.named || []).forEach(function (s) {
52588                   return branch.excludeNamed.set(s, new RegExp(s, 'i'));
52589                 });
52590                 var excludeRegexes = [].concat(_toConsumableArray(branch.excludeGeneric.values()), _toConsumableArray(branch.excludeNamed.values())); // ADD ITEMS
52591
52592                 var items = category.items;
52593                 if (!Array.isArray(items) || !items.length) return; // Primary name patterns, match tags to take first
52594                 //  e.g. `name`, `name:ru`
52595
52596                 var primaryName = new RegExp(tree.nameTags.primary, 'i'); // Alternate name patterns, match tags to consider after primary
52597                 //  e.g. `alt_name`, `short_name`, `brand`, `brand:ru`, etc..
52598
52599                 var alternateName = new RegExp(tree.nameTags.alternate, 'i'); // There are a few exceptions to the name matching regexes.
52600                 // Usually a tag suffix contains a language code like `name:en`, `name:ru`
52601                 // but we want to exclude things like `operator:type`, `name:etymology`, etc..
52602
52603                 var notName = /:(colou?r|type|forward|backward|left|right|etymology|pronunciation|wikipedia)$/i; // For certain categories we do not want to match generic KV pairs like `building/yes` or `amenity/yes`
52604
52605                 var skipGenericKV = skipGenericKVMatches(t, k, v); // We will collect the generic KV pairs anyway (for the purpose of filtering them out of matchTags)
52606
52607                 var genericKV = new Set(["".concat(k, "/yes"), "building/yes"]); // Collect alternate tagpairs for this kv category from matchGroups.
52608                 // We might also pick up a few more generic KVs (like `shop/yes`)
52609
52610                 var matchGroupKV = new Set();
52611                 Object.values(matchGroups).forEach(function (matchGroup) {
52612                   var inGroup = matchGroup.some(function (otherkv) {
52613                     return otherkv === thiskv;
52614                   });
52615                   if (!inGroup) return;
52616                   matchGroup.forEach(function (otherkv) {
52617                     if (otherkv === thiskv) return; // skip self
52618
52619                     matchGroupKV.add(otherkv);
52620                     var otherk = otherkv.split('/', 2)[0]; // we might pick up a `shop/yes`
52621
52622                     genericKV.add("".concat(otherk, "/yes"));
52623                   });
52624                 }); // For each item, insert all [key, value, name] combinations into the match index
52625
52626                 items.forEach(function (item) {
52627                   if (!item.id) return; // Automatically remove redundant `matchTags` - #3417
52628                   // (i.e. This kv is already covered by matchGroups, so it doesn't need to be in `item.matchTags`)
52629
52630                   if (Array.isArray(item.matchTags) && item.matchTags.length) {
52631                     item.matchTags = item.matchTags.filter(function (matchTag) {
52632                       return !matchGroupKV.has(matchTag) && !genericKV.has(matchTag);
52633                     });
52634                     if (!item.matchTags.length) delete item.matchTags;
52635                   } // key/value tagpairs to insert into the match index..
52636
52637
52638                   var kvTags = ["".concat(thiskv)].concat(item.matchTags || []);
52639
52640                   if (!skipGenericKV) {
52641                     kvTags = kvTags.concat(Array.from(genericKV)); // #3454 - match some generic tags
52642                   } // Index all the namelike tag values
52643
52644
52645                   Object.keys(item.tags).forEach(function (osmkey) {
52646                     if (notName.test(osmkey)) return; // osmkey is not a namelike tag, skip
52647
52648                     var osmvalue = item.tags[osmkey];
52649                     if (!osmvalue || excludeRegexes.some(function (regex) {
52650                       return regex.test(osmvalue);
52651                     })) return; // osmvalue missing or excluded
52652
52653                     if (primaryName.test(osmkey)) {
52654                       kvTags.forEach(function (kv) {
52655                         return insertName('primary', kv, simplify$1(osmvalue), item.id);
52656                       });
52657                     } else if (alternateName.test(osmkey)) {
52658                       kvTags.forEach(function (kv) {
52659                         return insertName('alternate', kv, simplify$1(osmvalue), item.id);
52660                       });
52661                     }
52662                   }); // Index `matchNames` after indexing all other names..
52663
52664                   var keepMatchNames = new Set();
52665                   (item.matchNames || []).forEach(function (matchName) {
52666                     // If this matchname isn't already indexed, add it to the alternate index
52667                     var nsimple = simplify$1(matchName);
52668                     kvTags.forEach(function (kv) {
52669                       var branch = that.matchIndex.get(kv);
52670                       var primaryLeaf = branch && branch.primary.get(nsimple);
52671                       var alternateLeaf = branch && branch.alternate.get(nsimple);
52672                       var inPrimary = primaryLeaf && primaryLeaf.has(item.id);
52673                       var inAlternate = alternateLeaf && alternateLeaf.has(item.id);
52674
52675                       if (!inPrimary && !inAlternate) {
52676                         insertName('alternate', kv, nsimple, item.id);
52677                         keepMatchNames.add(matchName);
52678                       }
52679                     });
52680                   }); // Automatically remove redundant `matchNames` - #3417
52681                   // (i.e. This name got indexed some other way, so it doesn't need to be in `item.matchNames`)
52682
52683                   if (keepMatchNames.size) {
52684                     item.matchNames = Array.from(keepMatchNames);
52685                   } else {
52686                     delete item.matchNames;
52687                   }
52688                 }); // each item
52689               }); // each tkv
52690               // Insert this item into the matchIndex
52691
52692               function insertName(which, kv, nsimple, itemID) {
52693                 if (!nsimple) return;
52694                 var branch = that.matchIndex.get(kv);
52695
52696                 if (!branch) {
52697                   branch = {
52698                     primary: new Map(),
52699                     alternate: new Map(),
52700                     excludeGeneric: new Map(),
52701                     excludeNamed: new Map()
52702                   };
52703                   that.matchIndex.set(kv, branch);
52704                 }
52705
52706                 var leaf = branch[which].get(nsimple);
52707
52708                 if (!leaf) {
52709                   leaf = new Set();
52710                   branch[which].set(nsimple, leaf);
52711                 }
52712
52713                 leaf.add(itemID); // insert
52714               } // For certain categories we do not want to match generic KV pairs like `building/yes` or `amenity/yes`
52715
52716
52717               function skipGenericKVMatches(t, k, v) {
52718                 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';
52719               }
52720             } //
52721             // `buildLocationIndex()`
52722             // Call this to prepare a which-polygon location index.
52723             // This *resolves* all the locationSets into GeoJSON, which takes some time.
52724             // You can skip this step if you don't care about matching within a location.
52725             //
52726             // `data` needs to be an Object indexed on a 'tree/key/value' path.
52727             // (e.g. cache filled by `fileTree.read` or data found in `dist/nsi.json`)
52728             // {
52729             //    'brands/amenity/bank': { properties: {}, items: [ {}, {}, … ] },
52730             //    'brands/amenity/bar':  { properties: {}, items: [ {}, {}, … ] },
52731             //    …
52732             // }
52733             //
52734
52735           }, {
52736             key: "buildLocationIndex",
52737             value: function buildLocationIndex(data, loco) {
52738               var that = this;
52739               if (that.locationIndex) return; // it was built already
52740
52741               that.itemLocation = new Map();
52742               that.locationSets = new Map();
52743               Object.keys(data).forEach(function (tkv) {
52744                 var items = data[tkv].items;
52745                 if (!Array.isArray(items) || !items.length) return;
52746                 items.forEach(function (item) {
52747                   if (that.itemLocation.has(item.id)) return; // we've seen item id already - shouldn't be possible?
52748
52749                   var resolved;
52750
52751                   try {
52752                     resolved = loco.resolveLocationSet(item.locationSet); // resolve a feature for this locationSet
52753                   } catch (err) {
52754                     console.warn("buildLocationIndex: ".concat(err.message)); // couldn't resolve
52755                   }
52756
52757                   if (!resolved || !resolved.id) return;
52758                   that.itemLocation.set(item.id, resolved.id); // link it to the item
52759
52760                   if (that.locationSets.has(resolved.id)) return; // we've seen this locationSet feature before..
52761                   // First time seeing this locationSet feature, make a copy and add to locationSet cache..
52762
52763                   var feature = _cloneDeep(resolved.feature);
52764
52765                   feature.id = resolved.id; // Important: always use the locationSet `id` (`+[Q30]`), not the feature `id` (`Q30`)
52766
52767                   feature.properties.id = resolved.id;
52768
52769                   if (!feature.geometry.coordinates.length || !feature.properties.area) {
52770                     console.warn("buildLocationIndex: locationSet ".concat(resolved.id, " for ").concat(item.id, " resolves to an empty feature:"));
52771                     console.warn(JSON.stringify(feature));
52772                     return;
52773                   }
52774
52775                   that.locationSets.set(resolved.id, feature);
52776                 });
52777               });
52778               that.locationIndex = whichPolygon_1({
52779                 type: 'FeatureCollection',
52780                 features: _toConsumableArray(that.locationSets.values())
52781               });
52782
52783               function _cloneDeep(obj) {
52784                 return JSON.parse(JSON.stringify(obj));
52785               }
52786             } //
52787             // `match()`
52788             // Pass parts and return an Array of matches.
52789             // `k` - key
52790             // `v` - value
52791             // `n` - namelike
52792             // `loc` - optional - [lon,lat] location to search
52793             //
52794             // 1. If the [k,v,n] tuple matches a canonical item…
52795             // Return an Array of match results.
52796             // Each result will include the area in km² that the item is valid.
52797             //
52798             // Order of results:
52799             // Primary ordering will be on the "match" column:
52800             //   "primary" - where the query matches the `name` tag, followed by
52801             //   "alternate" - where the query matches an alternate name tag (e.g. short_name, brand, operator, etc)
52802             // Secondary ordering will be on the "area" column:
52803             //   "area descending" if no location was provided, (worldwide before local)
52804             //   "area ascending" if location was provided (local before worldwide)
52805             //
52806             // [
52807             //   { match: 'primary',   itemID: String,  area: Number,  kv: String,  nsimple: String },
52808             //   { match: 'primary',   itemID: String,  area: Number,  kv: String,  nsimple: String },
52809             //   { match: 'alternate', itemID: String,  area: Number,  kv: String,  nsimple: String },
52810             //   { match: 'alternate', itemID: String,  area: Number,  kv: String,  nsimple: String },
52811             //   …
52812             // ]
52813             //
52814             // -or-
52815             //
52816             // 2. If the [k,v,n] tuple matches an exclude pattern…
52817             // Return an Array with a single exclude result, either
52818             //
52819             // [ { match: 'excludeGeneric', pattern: String,  kv: String } ]  // "generic" e.g. "Food Court"
52820             //   or
52821             // [ { match: 'excludeNamed', pattern: String,  kv: String } ]    // "named", e.g. "Kebabai"
52822             //
52823             // About results
52824             //   "generic" - a generic word that is probably not really a name.
52825             //     For these, iD should warn the user "Hey don't put 'food court' in the name tag".
52826             //   "named" - a real name like "Kebabai" that is just common, but not a brand.
52827             //     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.
52828             //
52829             // -or-
52830             //
52831             // 3. If the [k,v,n] tuple matches nothing of any kind, return `null`
52832             //
52833             //
52834
52835           }, {
52836             key: "match",
52837             value: function match(k, v, n, loc) {
52838               var that = this;
52839
52840               if (!that.matchIndex) {
52841                 throw new Error('match:  matchIndex not built.');
52842               } // If we were supplied a location, and a that.locationIndex has been set up,
52843               // get the locationSets that are valid there so we can filter results.
52844
52845
52846               var matchLocations;
52847
52848               if (Array.isArray(loc) && that.locationIndex) {
52849                 // which-polygon query returns an array of GeoJSON properties, pass true to return all results
52850                 matchLocations = that.locationIndex([loc[0], loc[1], loc[0], loc[1]], true);
52851               }
52852
52853               var nsimple = simplify$1(n);
52854               var seen = new Set();
52855               var results = [];
52856               gatherResults('primary');
52857               gatherResults('alternate');
52858               if (results.length) return results;
52859               gatherResults('exclude');
52860               return results.length ? results : null;
52861
52862               function gatherResults(which) {
52863                 // First try an exact match on k/v
52864                 var kv = "".concat(k, "/").concat(v);
52865                 var didMatch = tryMatch(which, kv);
52866                 if (didMatch) return; // If that didn't work, look in match groups for other pairs considered equivalent to k/v..
52867
52868                 for (var mg in matchGroups) {
52869                   var matchGroup = matchGroups[mg];
52870                   var inGroup = matchGroup.some(function (otherkv) {
52871                     return otherkv === kv;
52872                   });
52873                   if (!inGroup) continue;
52874
52875                   for (var i = 0; i < matchGroup.length; i++) {
52876                     var otherkv = matchGroup[i];
52877                     if (otherkv === kv) continue; // skip self
52878
52879                     didMatch = tryMatch(which, otherkv);
52880                     if (didMatch) return;
52881                   }
52882                 } // If finished 'exclude' pass and still haven't matched anything, try the global `genericWords.json` patterns
52883
52884
52885                 if (which === 'exclude') {
52886                   var regex = _toConsumableArray(that.genericWords.values()).find(function (regex) {
52887                     return regex.test(n);
52888                   });
52889
52890                   if (regex) {
52891                     results.push({
52892                       match: 'excludeGeneric',
52893                       pattern: String(regex)
52894                     }); // note no `branch`, no `kv`
52895
52896                     return;
52897                   }
52898                 }
52899               }
52900
52901               function tryMatch(which, kv) {
52902                 var branch = that.matchIndex.get(kv);
52903                 if (!branch) return;
52904
52905                 if (which === 'exclude') {
52906                   // Test name `n` against named and generic exclude patterns
52907                   var regex = _toConsumableArray(branch.excludeNamed.values()).find(function (regex) {
52908                     return regex.test(n);
52909                   });
52910
52911                   if (regex) {
52912                     results.push({
52913                       match: 'excludeNamed',
52914                       pattern: String(regex),
52915                       kv: kv
52916                     });
52917                     return;
52918                   }
52919
52920                   regex = _toConsumableArray(branch.excludeGeneric.values()).find(function (regex) {
52921                     return regex.test(n);
52922                   });
52923
52924                   if (regex) {
52925                     results.push({
52926                       match: 'excludeGeneric',
52927                       pattern: String(regex),
52928                       kv: kv
52929                     });
52930                     return;
52931                   }
52932
52933                   return;
52934                 }
52935
52936                 var leaf = branch[which].get(nsimple);
52937                 if (!leaf || !leaf.size) return; // If we get here, we matched something..
52938                 // Prepare the results, calculate areas (if location index was set up)
52939
52940                 var hits = Array.from(leaf).map(function (itemID) {
52941                   var area = Infinity;
52942
52943                   if (that.itemLocation && that.locationSets) {
52944                     var location = that.locationSets.get(that.itemLocation.get(itemID));
52945                     area = location && location.properties.area || Infinity;
52946                   }
52947
52948                   return {
52949                     match: which,
52950                     itemID: itemID,
52951                     area: area,
52952                     kv: kv,
52953                     nsimple: nsimple
52954                   };
52955                 });
52956                 var sortFn = byAreaDescending; // Filter the match to include only results valid in the requested `loc`..
52957
52958                 if (matchLocations) {
52959                   hits = hits.filter(isValidLocation);
52960                   sortFn = byAreaAscending;
52961                 }
52962
52963                 if (!hits.length) return; // push results
52964
52965                 hits.sort(sortFn).forEach(function (hit) {
52966                   if (seen.has(hit.itemID)) return;
52967                   seen.add(hit.itemID);
52968                   results.push(hit);
52969                 });
52970                 return true;
52971
52972                 function isValidLocation(hit) {
52973                   if (!that.itemLocation) return true;
52974                   return matchLocations.find(function (props) {
52975                     return props.id === that.itemLocation.get(hit.itemID);
52976                   });
52977                 } // Sort smaller (more local) locations first.
52978
52979
52980                 function byAreaAscending(hitA, hitB) {
52981                   return hitA.area - hitB.area;
52982                 } // Sort larger (more worldwide) locations first.
52983
52984
52985                 function byAreaDescending(hitA, hitB) {
52986                   return hitB.area - hitA.area;
52987                 }
52988               }
52989             } //
52990             // `getWarnings()`
52991             // Return any warnings discovered when buiding the index.
52992             // (currently this does nothing)
52993             //
52994
52995           }, {
52996             key: "getWarnings",
52997             value: function getWarnings() {
52998               return this.warnings;
52999             }
53000           }]);
53001
53002           return Matcher;
53003         }();
53004
53005         /**
53006          * Checks if `value` is the
53007          * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
53008          * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
53009          *
53010          * @static
53011          * @memberOf _
53012          * @since 0.1.0
53013          * @category Lang
53014          * @param {*} value The value to check.
53015          * @returns {boolean} Returns `true` if `value` is an object, else `false`.
53016          * @example
53017          *
53018          * _.isObject({});
53019          * // => true
53020          *
53021          * _.isObject([1, 2, 3]);
53022          * // => true
53023          *
53024          * _.isObject(_.noop);
53025          * // => true
53026          *
53027          * _.isObject(null);
53028          * // => false
53029          */
53030         function isObject$2(value) {
53031           var type = _typeof(value);
53032
53033           return value != null && (type == 'object' || type == 'function');
53034         }
53035
53036         /** Detect free variable `global` from Node.js. */
53037         var freeGlobal = (typeof global === "undefined" ? "undefined" : _typeof(global)) == 'object' && global && global.Object === Object && global;
53038
53039         /** Detect free variable `self`. */
53040
53041         var freeSelf = (typeof self === "undefined" ? "undefined" : _typeof(self)) == 'object' && self && self.Object === Object && self;
53042         /** Used as a reference to the global object. */
53043
53044         var root = freeGlobal || freeSelf || Function('return this')();
53045
53046         /**
53047          * Gets the timestamp of the number of milliseconds that have elapsed since
53048          * the Unix epoch (1 January 1970 00:00:00 UTC).
53049          *
53050          * @static
53051          * @memberOf _
53052          * @since 2.4.0
53053          * @category Date
53054          * @returns {number} Returns the timestamp.
53055          * @example
53056          *
53057          * _.defer(function(stamp) {
53058          *   console.log(_.now() - stamp);
53059          * }, _.now());
53060          * // => Logs the number of milliseconds it took for the deferred invocation.
53061          */
53062
53063         var now = function now() {
53064           return root.Date.now();
53065         };
53066
53067         /** Used to match a single whitespace character. */
53068         var reWhitespace = /\s/;
53069         /**
53070          * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
53071          * character of `string`.
53072          *
53073          * @private
53074          * @param {string} string The string to inspect.
53075          * @returns {number} Returns the index of the last non-whitespace character.
53076          */
53077
53078         function trimmedEndIndex(string) {
53079           var index = string.length;
53080
53081           while (index-- && reWhitespace.test(string.charAt(index))) {}
53082
53083           return index;
53084         }
53085
53086         /** Used to match leading whitespace. */
53087
53088         var reTrimStart = /^\s+/;
53089         /**
53090          * The base implementation of `_.trim`.
53091          *
53092          * @private
53093          * @param {string} string The string to trim.
53094          * @returns {string} Returns the trimmed string.
53095          */
53096
53097         function baseTrim(string) {
53098           return string ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '') : string;
53099         }
53100
53101         /** Built-in value references. */
53102
53103         var _Symbol = root.Symbol;
53104
53105         /** Used for built-in method references. */
53106
53107         var objectProto$1 = Object.prototype;
53108         /** Used to check objects for own properties. */
53109
53110         var hasOwnProperty$2 = objectProto$1.hasOwnProperty;
53111         /**
53112          * Used to resolve the
53113          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
53114          * of values.
53115          */
53116
53117         var nativeObjectToString$1 = objectProto$1.toString;
53118         /** Built-in value references. */
53119
53120         var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
53121         /**
53122          * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
53123          *
53124          * @private
53125          * @param {*} value The value to query.
53126          * @returns {string} Returns the raw `toStringTag`.
53127          */
53128
53129         function getRawTag(value) {
53130           var isOwn = hasOwnProperty$2.call(value, symToStringTag$1),
53131               tag = value[symToStringTag$1];
53132
53133           try {
53134             value[symToStringTag$1] = undefined;
53135             var unmasked = true;
53136           } catch (e) {}
53137
53138           var result = nativeObjectToString$1.call(value);
53139
53140           if (unmasked) {
53141             if (isOwn) {
53142               value[symToStringTag$1] = tag;
53143             } else {
53144               delete value[symToStringTag$1];
53145             }
53146           }
53147
53148           return result;
53149         }
53150
53151         /** Used for built-in method references. */
53152         var objectProto = Object.prototype;
53153         /**
53154          * Used to resolve the
53155          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
53156          * of values.
53157          */
53158
53159         var nativeObjectToString = objectProto.toString;
53160         /**
53161          * Converts `value` to a string using `Object.prototype.toString`.
53162          *
53163          * @private
53164          * @param {*} value The value to convert.
53165          * @returns {string} Returns the converted string.
53166          */
53167
53168         function objectToString(value) {
53169           return nativeObjectToString.call(value);
53170         }
53171
53172         /** `Object#toString` result references. */
53173
53174         var nullTag = '[object Null]',
53175             undefinedTag = '[object Undefined]';
53176         /** Built-in value references. */
53177
53178         var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
53179         /**
53180          * The base implementation of `getTag` without fallbacks for buggy environments.
53181          *
53182          * @private
53183          * @param {*} value The value to query.
53184          * @returns {string} Returns the `toStringTag`.
53185          */
53186
53187         function baseGetTag(value) {
53188           if (value == null) {
53189             return value === undefined ? undefinedTag : nullTag;
53190           }
53191
53192           return symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value);
53193         }
53194
53195         /**
53196          * Checks if `value` is object-like. A value is object-like if it's not `null`
53197          * and has a `typeof` result of "object".
53198          *
53199          * @static
53200          * @memberOf _
53201          * @since 4.0.0
53202          * @category Lang
53203          * @param {*} value The value to check.
53204          * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
53205          * @example
53206          *
53207          * _.isObjectLike({});
53208          * // => true
53209          *
53210          * _.isObjectLike([1, 2, 3]);
53211          * // => true
53212          *
53213          * _.isObjectLike(_.noop);
53214          * // => false
53215          *
53216          * _.isObjectLike(null);
53217          * // => false
53218          */
53219         function isObjectLike(value) {
53220           return value != null && _typeof(value) == 'object';
53221         }
53222
53223         /** `Object#toString` result references. */
53224
53225         var symbolTag = '[object Symbol]';
53226         /**
53227          * Checks if `value` is classified as a `Symbol` primitive or object.
53228          *
53229          * @static
53230          * @memberOf _
53231          * @since 4.0.0
53232          * @category Lang
53233          * @param {*} value The value to check.
53234          * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
53235          * @example
53236          *
53237          * _.isSymbol(Symbol.iterator);
53238          * // => true
53239          *
53240          * _.isSymbol('abc');
53241          * // => false
53242          */
53243
53244         function isSymbol(value) {
53245           return _typeof(value) == 'symbol' || isObjectLike(value) && baseGetTag(value) == symbolTag;
53246         }
53247
53248         /** Used as references for various `Number` constants. */
53249
53250         var NAN = 0 / 0;
53251         /** Used to detect bad signed hexadecimal string values. */
53252
53253         var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
53254         /** Used to detect binary string values. */
53255
53256         var reIsBinary = /^0b[01]+$/i;
53257         /** Used to detect octal string values. */
53258
53259         var reIsOctal = /^0o[0-7]+$/i;
53260         /** Built-in method references without a dependency on `root`. */
53261
53262         var freeParseInt = parseInt;
53263         /**
53264          * Converts `value` to a number.
53265          *
53266          * @static
53267          * @memberOf _
53268          * @since 4.0.0
53269          * @category Lang
53270          * @param {*} value The value to process.
53271          * @returns {number} Returns the number.
53272          * @example
53273          *
53274          * _.toNumber(3.2);
53275          * // => 3.2
53276          *
53277          * _.toNumber(Number.MIN_VALUE);
53278          * // => 5e-324
53279          *
53280          * _.toNumber(Infinity);
53281          * // => Infinity
53282          *
53283          * _.toNumber('3.2');
53284          * // => 3.2
53285          */
53286
53287         function toNumber(value) {
53288           if (typeof value == 'number') {
53289             return value;
53290           }
53291
53292           if (isSymbol(value)) {
53293             return NAN;
53294           }
53295
53296           if (isObject$2(value)) {
53297             var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
53298             value = isObject$2(other) ? other + '' : other;
53299           }
53300
53301           if (typeof value != 'string') {
53302             return value === 0 ? value : +value;
53303           }
53304
53305           value = baseTrim(value);
53306           var isBinary = reIsBinary.test(value);
53307           return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
53308         }
53309
53310         /** Error message constants. */
53311
53312         var FUNC_ERROR_TEXT$1 = 'Expected a function';
53313         /* Built-in method references for those with the same name as other `lodash` methods. */
53314
53315         var nativeMax = Math.max,
53316             nativeMin = Math.min;
53317         /**
53318          * Creates a debounced function that delays invoking `func` until after `wait`
53319          * milliseconds have elapsed since the last time the debounced function was
53320          * invoked. The debounced function comes with a `cancel` method to cancel
53321          * delayed `func` invocations and a `flush` method to immediately invoke them.
53322          * Provide `options` to indicate whether `func` should be invoked on the
53323          * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
53324          * with the last arguments provided to the debounced function. Subsequent
53325          * calls to the debounced function return the result of the last `func`
53326          * invocation.
53327          *
53328          * **Note:** If `leading` and `trailing` options are `true`, `func` is
53329          * invoked on the trailing edge of the timeout only if the debounced function
53330          * is invoked more than once during the `wait` timeout.
53331          *
53332          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
53333          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
53334          *
53335          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
53336          * for details over the differences between `_.debounce` and `_.throttle`.
53337          *
53338          * @static
53339          * @memberOf _
53340          * @since 0.1.0
53341          * @category Function
53342          * @param {Function} func The function to debounce.
53343          * @param {number} [wait=0] The number of milliseconds to delay.
53344          * @param {Object} [options={}] The options object.
53345          * @param {boolean} [options.leading=false]
53346          *  Specify invoking on the leading edge of the timeout.
53347          * @param {number} [options.maxWait]
53348          *  The maximum time `func` is allowed to be delayed before it's invoked.
53349          * @param {boolean} [options.trailing=true]
53350          *  Specify invoking on the trailing edge of the timeout.
53351          * @returns {Function} Returns the new debounced function.
53352          * @example
53353          *
53354          * // Avoid costly calculations while the window size is in flux.
53355          * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
53356          *
53357          * // Invoke `sendMail` when clicked, debouncing subsequent calls.
53358          * jQuery(element).on('click', _.debounce(sendMail, 300, {
53359          *   'leading': true,
53360          *   'trailing': false
53361          * }));
53362          *
53363          * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
53364          * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
53365          * var source = new EventSource('/stream');
53366          * jQuery(source).on('message', debounced);
53367          *
53368          * // Cancel the trailing debounced invocation.
53369          * jQuery(window).on('popstate', debounced.cancel);
53370          */
53371
53372         function debounce(func, wait, options) {
53373           var lastArgs,
53374               lastThis,
53375               maxWait,
53376               result,
53377               timerId,
53378               lastCallTime,
53379               lastInvokeTime = 0,
53380               leading = false,
53381               maxing = false,
53382               trailing = true;
53383
53384           if (typeof func != 'function') {
53385             throw new TypeError(FUNC_ERROR_TEXT$1);
53386           }
53387
53388           wait = toNumber(wait) || 0;
53389
53390           if (isObject$2(options)) {
53391             leading = !!options.leading;
53392             maxing = 'maxWait' in options;
53393             maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
53394             trailing = 'trailing' in options ? !!options.trailing : trailing;
53395           }
53396
53397           function invokeFunc(time) {
53398             var args = lastArgs,
53399                 thisArg = lastThis;
53400             lastArgs = lastThis = undefined;
53401             lastInvokeTime = time;
53402             result = func.apply(thisArg, args);
53403             return result;
53404           }
53405
53406           function leadingEdge(time) {
53407             // Reset any `maxWait` timer.
53408             lastInvokeTime = time; // Start the timer for the trailing edge.
53409
53410             timerId = setTimeout(timerExpired, wait); // Invoke the leading edge.
53411
53412             return leading ? invokeFunc(time) : result;
53413           }
53414
53415           function remainingWait(time) {
53416             var timeSinceLastCall = time - lastCallTime,
53417                 timeSinceLastInvoke = time - lastInvokeTime,
53418                 timeWaiting = wait - timeSinceLastCall;
53419             return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
53420           }
53421
53422           function shouldInvoke(time) {
53423             var timeSinceLastCall = time - lastCallTime,
53424                 timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the
53425             // trailing edge, the system time has gone backwards and we're treating
53426             // it as the trailing edge, or we've hit the `maxWait` limit.
53427
53428             return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
53429           }
53430
53431           function timerExpired() {
53432             var time = now();
53433
53434             if (shouldInvoke(time)) {
53435               return trailingEdge(time);
53436             } // Restart the timer.
53437
53438
53439             timerId = setTimeout(timerExpired, remainingWait(time));
53440           }
53441
53442           function trailingEdge(time) {
53443             timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been
53444             // debounced at least once.
53445
53446             if (trailing && lastArgs) {
53447               return invokeFunc(time);
53448             }
53449
53450             lastArgs = lastThis = undefined;
53451             return result;
53452           }
53453
53454           function cancel() {
53455             if (timerId !== undefined) {
53456               clearTimeout(timerId);
53457             }
53458
53459             lastInvokeTime = 0;
53460             lastArgs = lastCallTime = lastThis = timerId = undefined;
53461           }
53462
53463           function flush() {
53464             return timerId === undefined ? result : trailingEdge(now());
53465           }
53466
53467           function debounced() {
53468             var time = now(),
53469                 isInvoking = shouldInvoke(time);
53470             lastArgs = arguments;
53471             lastThis = this;
53472             lastCallTime = time;
53473
53474             if (isInvoking) {
53475               if (timerId === undefined) {
53476                 return leadingEdge(lastCallTime);
53477               }
53478
53479               if (maxing) {
53480                 // Handle invocations in a tight loop.
53481                 clearTimeout(timerId);
53482                 timerId = setTimeout(timerExpired, wait);
53483                 return invokeFunc(lastCallTime);
53484               }
53485             }
53486
53487             if (timerId === undefined) {
53488               timerId = setTimeout(timerExpired, wait);
53489             }
53490
53491             return result;
53492           }
53493
53494           debounced.cancel = cancel;
53495           debounced.flush = flush;
53496           return debounced;
53497         }
53498
53499         /*
53500             iD.coreDifference represents the difference between two graphs.
53501             It knows how to calculate the set of entities that were
53502             created, modified, or deleted, and also contains the logic
53503             for recursively extending a difference to the complete set
53504             of entities that will require a redraw, taking into account
53505             child and parent relationships.
53506          */
53507
53508         function coreDifference(base, head) {
53509           var _changes = {};
53510           var _didChange = {}; // 'addition', 'deletion', 'geometry', 'properties'
53511
53512           var _diff = {};
53513
53514           function checkEntityID(id) {
53515             var h = head.entities[id];
53516             var b = base.entities[id];
53517             if (h === b) return;
53518             if (_changes[id]) return;
53519
53520             if (!h && b) {
53521               _changes[id] = {
53522                 base: b,
53523                 head: h
53524               };
53525               _didChange.deletion = true;
53526               return;
53527             }
53528
53529             if (h && !b) {
53530               _changes[id] = {
53531                 base: b,
53532                 head: h
53533               };
53534               _didChange.addition = true;
53535               return;
53536             }
53537
53538             if (h && b) {
53539               if (h.members && b.members && !fastDeepEqual(h.members, b.members)) {
53540                 _changes[id] = {
53541                   base: b,
53542                   head: h
53543                 };
53544                 _didChange.geometry = true;
53545                 _didChange.properties = true;
53546                 return;
53547               }
53548
53549               if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
53550                 _changes[id] = {
53551                   base: b,
53552                   head: h
53553                 };
53554                 _didChange.geometry = true;
53555               }
53556
53557               if (h.nodes && b.nodes && !fastDeepEqual(h.nodes, b.nodes)) {
53558                 _changes[id] = {
53559                   base: b,
53560                   head: h
53561                 };
53562                 _didChange.geometry = true;
53563               }
53564
53565               if (h.tags && b.tags && !fastDeepEqual(h.tags, b.tags)) {
53566                 _changes[id] = {
53567                   base: b,
53568                   head: h
53569                 };
53570                 _didChange.properties = true;
53571               }
53572             }
53573           }
53574
53575           function load() {
53576             // HOT CODE: there can be many thousands of downloaded entities, so looping
53577             // through them all can become a performance bottleneck. Optimize by
53578             // resolving duplicates and using a basic `for` loop
53579             var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
53580
53581             for (var i = 0; i < ids.length; i++) {
53582               checkEntityID(ids[i]);
53583             }
53584           }
53585
53586           load();
53587
53588           _diff.length = function length() {
53589             return Object.keys(_changes).length;
53590           };
53591
53592           _diff.changes = function changes() {
53593             return _changes;
53594           };
53595
53596           _diff.didChange = _didChange; // pass true to include affected relation members
53597
53598           _diff.extantIDs = function extantIDs(includeRelMembers) {
53599             var result = new Set();
53600             Object.keys(_changes).forEach(function (id) {
53601               if (_changes[id].head) {
53602                 result.add(id);
53603               }
53604
53605               var h = _changes[id].head;
53606               var b = _changes[id].base;
53607               var entity = h || b;
53608
53609               if (includeRelMembers && entity.type === 'relation') {
53610                 var mh = h ? h.members.map(function (m) {
53611                   return m.id;
53612                 }) : [];
53613                 var mb = b ? b.members.map(function (m) {
53614                   return m.id;
53615                 }) : [];
53616                 utilArrayUnion(mh, mb).forEach(function (memberID) {
53617                   if (head.hasEntity(memberID)) {
53618                     result.add(memberID);
53619                   }
53620                 });
53621               }
53622             });
53623             return Array.from(result);
53624           };
53625
53626           _diff.modified = function modified() {
53627             var result = [];
53628             Object.values(_changes).forEach(function (change) {
53629               if (change.base && change.head) {
53630                 result.push(change.head);
53631               }
53632             });
53633             return result;
53634           };
53635
53636           _diff.created = function created() {
53637             var result = [];
53638             Object.values(_changes).forEach(function (change) {
53639               if (!change.base && change.head) {
53640                 result.push(change.head);
53641               }
53642             });
53643             return result;
53644           };
53645
53646           _diff.deleted = function deleted() {
53647             var result = [];
53648             Object.values(_changes).forEach(function (change) {
53649               if (change.base && !change.head) {
53650                 result.push(change.base);
53651               }
53652             });
53653             return result;
53654           };
53655
53656           _diff.summary = function summary() {
53657             var relevant = {};
53658             var keys = Object.keys(_changes);
53659
53660             for (var i = 0; i < keys.length; i++) {
53661               var change = _changes[keys[i]];
53662
53663               if (change.head && change.head.geometry(head) !== 'vertex') {
53664                 addEntity(change.head, head, change.base ? 'modified' : 'created');
53665               } else if (change.base && change.base.geometry(base) !== 'vertex') {
53666                 addEntity(change.base, base, 'deleted');
53667               } else if (change.base && change.head) {
53668                 // modified vertex
53669                 var moved = !fastDeepEqual(change.base.loc, change.head.loc);
53670                 var retagged = !fastDeepEqual(change.base.tags, change.head.tags);
53671
53672                 if (moved) {
53673                   addParents(change.head);
53674                 }
53675
53676                 if (retagged || moved && change.head.hasInterestingTags()) {
53677                   addEntity(change.head, head, 'modified');
53678                 }
53679               } else if (change.head && change.head.hasInterestingTags()) {
53680                 // created vertex
53681                 addEntity(change.head, head, 'created');
53682               } else if (change.base && change.base.hasInterestingTags()) {
53683                 // deleted vertex
53684                 addEntity(change.base, base, 'deleted');
53685               }
53686             }
53687
53688             return Object.values(relevant);
53689
53690             function addEntity(entity, graph, changeType) {
53691               relevant[entity.id] = {
53692                 entity: entity,
53693                 graph: graph,
53694                 changeType: changeType
53695               };
53696             }
53697
53698             function addParents(entity) {
53699               var parents = head.parentWays(entity);
53700
53701               for (var j = parents.length - 1; j >= 0; j--) {
53702                 var parent = parents[j];
53703
53704                 if (!(parent.id in relevant)) {
53705                   addEntity(parent, head, 'modified');
53706                 }
53707               }
53708             }
53709           }; // returns complete set of entities that require a redraw
53710           //  (optionally within given `extent`)
53711
53712
53713           _diff.complete = function complete(extent) {
53714             var result = {};
53715             var id, change;
53716
53717             for (id in _changes) {
53718               change = _changes[id];
53719               var h = change.head;
53720               var b = change.base;
53721               var entity = h || b;
53722               var i;
53723
53724               if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) {
53725                 continue;
53726               }
53727
53728               result[id] = h;
53729
53730               if (entity.type === 'way') {
53731                 var nh = h ? h.nodes : [];
53732                 var nb = b ? b.nodes : [];
53733                 var diff;
53734                 diff = utilArrayDifference(nh, nb);
53735
53736                 for (i = 0; i < diff.length; i++) {
53737                   result[diff[i]] = head.hasEntity(diff[i]);
53738                 }
53739
53740                 diff = utilArrayDifference(nb, nh);
53741
53742                 for (i = 0; i < diff.length; i++) {
53743                   result[diff[i]] = head.hasEntity(diff[i]);
53744                 }
53745               }
53746
53747               if (entity.type === 'relation' && entity.isMultipolygon()) {
53748                 var mh = h ? h.members.map(function (m) {
53749                   return m.id;
53750                 }) : [];
53751                 var mb = b ? b.members.map(function (m) {
53752                   return m.id;
53753                 }) : [];
53754                 var ids = utilArrayUnion(mh, mb);
53755
53756                 for (i = 0; i < ids.length; i++) {
53757                   var member = head.hasEntity(ids[i]);
53758                   if (!member) continue; // not downloaded
53759
53760                   if (extent && !member.intersects(extent, head)) continue; // not visible
53761
53762                   result[ids[i]] = member;
53763                 }
53764               }
53765
53766               addParents(head.parentWays(entity), result);
53767               addParents(head.parentRelations(entity), result);
53768             }
53769
53770             return result;
53771
53772             function addParents(parents, result) {
53773               for (var i = 0; i < parents.length; i++) {
53774                 var parent = parents[i];
53775                 if (parent.id in result) continue;
53776                 result[parent.id] = parent;
53777                 addParents(head.parentRelations(parent), result);
53778               }
53779             }
53780           };
53781
53782           return _diff;
53783         }
53784
53785         function coreTree(head) {
53786           // tree for entities
53787           var _rtree = new RBush();
53788
53789           var _bboxes = {}; // maintain a separate tree for granular way segments
53790
53791           var _segmentsRTree = new RBush();
53792
53793           var _segmentsBBoxes = {};
53794           var _segmentsByWayId = {};
53795           var tree = {};
53796
53797           function entityBBox(entity) {
53798             var bbox = entity.extent(head).bbox();
53799             bbox.id = entity.id;
53800             _bboxes[entity.id] = bbox;
53801             return bbox;
53802           }
53803
53804           function segmentBBox(segment) {
53805             var extent = segment.extent(head); // extent can be null if the node entities aren't in the graph for some reason
53806
53807             if (!extent) return null;
53808             var bbox = extent.bbox();
53809             bbox.segment = segment;
53810             _segmentsBBoxes[segment.id] = bbox;
53811             return bbox;
53812           }
53813
53814           function removeEntity(entity) {
53815             _rtree.remove(_bboxes[entity.id]);
53816
53817             delete _bboxes[entity.id];
53818
53819             if (_segmentsByWayId[entity.id]) {
53820               _segmentsByWayId[entity.id].forEach(function (segment) {
53821                 _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
53822
53823                 delete _segmentsBBoxes[segment.id];
53824               });
53825
53826               delete _segmentsByWayId[entity.id];
53827             }
53828           }
53829
53830           function loadEntities(entities) {
53831             _rtree.load(entities.map(entityBBox));
53832
53833             var segments = [];
53834             entities.forEach(function (entity) {
53835               if (entity.segments) {
53836                 var entitySegments = entity.segments(head); // cache these to make them easy to remove later
53837
53838                 _segmentsByWayId[entity.id] = entitySegments;
53839                 segments = segments.concat(entitySegments);
53840               }
53841             });
53842             if (segments.length) _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
53843           }
53844
53845           function updateParents(entity, insertions, memo) {
53846             head.parentWays(entity).forEach(function (way) {
53847               if (_bboxes[way.id]) {
53848                 removeEntity(way);
53849                 insertions[way.id] = way;
53850               }
53851
53852               updateParents(way, insertions, memo);
53853             });
53854             head.parentRelations(entity).forEach(function (relation) {
53855               if (memo[entity.id]) return;
53856               memo[entity.id] = true;
53857
53858               if (_bboxes[relation.id]) {
53859                 removeEntity(relation);
53860                 insertions[relation.id] = relation;
53861               }
53862
53863               updateParents(relation, insertions, memo);
53864             });
53865           }
53866
53867           tree.rebase = function (entities, force) {
53868             var insertions = {};
53869
53870             for (var i = 0; i < entities.length; i++) {
53871               var entity = entities[i];
53872               if (!entity.visible) continue;
53873
53874               if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
53875                 if (!force) {
53876                   continue;
53877                 } else if (_bboxes[entity.id]) {
53878                   removeEntity(entity);
53879                 }
53880               }
53881
53882               insertions[entity.id] = entity;
53883               updateParents(entity, insertions, {});
53884             }
53885
53886             loadEntities(Object.values(insertions));
53887             return tree;
53888           };
53889
53890           function updateToGraph(graph) {
53891             if (graph === head) return;
53892             var diff = coreDifference(head, graph);
53893             head = graph;
53894             var changed = diff.didChange;
53895             if (!changed.addition && !changed.deletion && !changed.geometry) return;
53896             var insertions = {};
53897
53898             if (changed.deletion) {
53899               diff.deleted().forEach(function (entity) {
53900                 removeEntity(entity);
53901               });
53902             }
53903
53904             if (changed.geometry) {
53905               diff.modified().forEach(function (entity) {
53906                 removeEntity(entity);
53907                 insertions[entity.id] = entity;
53908                 updateParents(entity, insertions, {});
53909               });
53910             }
53911
53912             if (changed.addition) {
53913               diff.created().forEach(function (entity) {
53914                 insertions[entity.id] = entity;
53915               });
53916             }
53917
53918             loadEntities(Object.values(insertions));
53919           } // returns an array of entities with bounding boxes overlapping `extent` for the given `graph`
53920
53921
53922           tree.intersects = function (extent, graph) {
53923             updateToGraph(graph);
53924             return _rtree.search(extent.bbox()).map(function (bbox) {
53925               return graph.entity(bbox.id);
53926             });
53927           }; // returns an array of segment objects with bounding boxes overlapping `extent` for the given `graph`
53928
53929
53930           tree.waySegments = function (extent, graph) {
53931             updateToGraph(graph);
53932             return _segmentsRTree.search(extent.bbox()).map(function (bbox) {
53933               return bbox.segment;
53934             });
53935           };
53936
53937           return tree;
53938         }
53939
53940         function svgIcon(name, svgklass, useklass) {
53941           return function drawIcon(selection) {
53942             selection.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);
53943           };
53944         }
53945
53946         function uiModal(selection, blocking) {
53947           var _this = this;
53948
53949           var keybinding = utilKeybinding('modal');
53950           var previous = selection.select('div.modal');
53951           var animate = previous.empty();
53952           previous.transition().duration(200).style('opacity', 0).remove();
53953           var shaded = selection.append('div').attr('class', 'shaded').style('opacity', 0);
53954
53955           shaded.close = function () {
53956             shaded.transition().duration(200).style('opacity', 0).remove();
53957             modal.transition().duration(200).style('top', '0px');
53958             select(document).call(keybinding.unbind);
53959           };
53960
53961           var modal = shaded.append('div').attr('class', 'modal fillL');
53962           modal.append('input').attr('class', 'keytrap keytrap-first').on('focus.keytrap', moveFocusToLast);
53963
53964           if (!blocking) {
53965             shaded.on('click.remove-modal', function (d3_event) {
53966               if (d3_event.target === _this) {
53967                 shaded.close();
53968               }
53969             });
53970             modal.append('button').attr('class', 'close').on('click', shaded.close).call(svgIcon('#iD-icon-close'));
53971             keybinding.on('⌫', shaded.close).on('⎋', shaded.close);
53972             select(document).call(keybinding);
53973           }
53974
53975           modal.append('div').attr('class', 'content');
53976           modal.append('input').attr('class', 'keytrap keytrap-last').on('focus.keytrap', moveFocusToFirst);
53977
53978           if (animate) {
53979             shaded.transition().style('opacity', 1);
53980           } else {
53981             shaded.style('opacity', 1);
53982           }
53983
53984           return shaded;
53985
53986           function moveFocusToFirst() {
53987             var node = modal // there are additional rules about what's focusable, but this suits our purposes
53988             .select('a, button, input:not(.keytrap), select, textarea').node();
53989
53990             if (node) {
53991               node.focus();
53992             } else {
53993               select(this).node().blur();
53994             }
53995           }
53996
53997           function moveFocusToLast() {
53998             var nodes = modal.selectAll('a, button, input:not(.keytrap), select, textarea').nodes();
53999
54000             if (nodes.length) {
54001               nodes[nodes.length - 1].focus();
54002             } else {
54003               select(this).node().blur();
54004             }
54005           }
54006         }
54007
54008         function uiLoading(context) {
54009           var _modalSelection = select(null);
54010
54011           var _message = '';
54012           var _blocking = false;
54013
54014           var loading = function loading(selection) {
54015             _modalSelection = uiModal(selection, _blocking);
54016
54017             var loadertext = _modalSelection.select('.content').classed('loading-modal', true).append('div').attr('class', 'modal-section fillL');
54018
54019             loadertext.append('img').attr('class', 'loader').attr('src', context.imagePath('loader-white.gif'));
54020             loadertext.append('h3').html(_message);
54021
54022             _modalSelection.select('button.close').attr('class', 'hide');
54023
54024             return loading;
54025           };
54026
54027           loading.message = function (val) {
54028             if (!arguments.length) return _message;
54029             _message = val;
54030             return loading;
54031           };
54032
54033           loading.blocking = function (val) {
54034             if (!arguments.length) return _blocking;
54035             _blocking = val;
54036             return loading;
54037           };
54038
54039           loading.close = function () {
54040             _modalSelection.remove();
54041           };
54042
54043           loading.isShown = function () {
54044             return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
54045           };
54046
54047           return loading;
54048         }
54049
54050         function coreHistory(context) {
54051           var dispatch = dispatch$8('reset', 'change', 'merge', 'restore', 'undone', 'redone');
54052
54053           var _lock = utilSessionMutex('lock'); // restorable if iD not open in another window/tab and a saved history exists in localStorage
54054
54055
54056           var _hasUnresolvedRestorableChanges = _lock.lock() && !!corePreferences(getKey('saved_history'));
54057
54058           var duration = 150;
54059           var _imageryUsed = [];
54060           var _photoOverlaysUsed = [];
54061           var _checkpoints = {};
54062
54063           var _pausedGraph;
54064
54065           var _stack;
54066
54067           var _index;
54068
54069           var _tree; // internal _act, accepts list of actions and eased time
54070
54071
54072           function _act(actions, t) {
54073             actions = Array.prototype.slice.call(actions);
54074             var annotation;
54075
54076             if (typeof actions[actions.length - 1] !== 'function') {
54077               annotation = actions.pop();
54078             }
54079
54080             var graph = _stack[_index].graph;
54081
54082             for (var i = 0; i < actions.length; i++) {
54083               graph = actions[i](graph, t);
54084             }
54085
54086             return {
54087               graph: graph,
54088               annotation: annotation,
54089               imageryUsed: _imageryUsed,
54090               photoOverlaysUsed: _photoOverlaysUsed,
54091               transform: context.projection.transform(),
54092               selectedIDs: context.selectedIDs()
54093             };
54094           } // internal _perform with eased time
54095
54096
54097           function _perform(args, t) {
54098             var previous = _stack[_index].graph;
54099             _stack = _stack.slice(0, _index + 1);
54100
54101             var actionResult = _act(args, t);
54102
54103             _stack.push(actionResult);
54104
54105             _index++;
54106             return change(previous);
54107           } // internal _replace with eased time
54108
54109
54110           function _replace(args, t) {
54111             var previous = _stack[_index].graph; // assert(_index == _stack.length - 1)
54112
54113             var actionResult = _act(args, t);
54114
54115             _stack[_index] = actionResult;
54116             return change(previous);
54117           } // internal _overwrite with eased time
54118
54119
54120           function _overwrite(args, t) {
54121             var previous = _stack[_index].graph;
54122
54123             if (_index > 0) {
54124               _index--;
54125
54126               _stack.pop();
54127             }
54128
54129             _stack = _stack.slice(0, _index + 1);
54130
54131             var actionResult = _act(args, t);
54132
54133             _stack.push(actionResult);
54134
54135             _index++;
54136             return change(previous);
54137           } // determine difference and dispatch a change event
54138
54139
54140           function change(previous) {
54141             var difference = coreDifference(previous, history.graph());
54142
54143             if (!_pausedGraph) {
54144               dispatch.call('change', this, difference);
54145             }
54146
54147             return difference;
54148           } // iD uses namespaced keys so multiple installations do not conflict
54149
54150
54151           function getKey(n) {
54152             return 'iD_' + window.location.origin + '_' + n;
54153           }
54154
54155           var history = {
54156             graph: function graph() {
54157               return _stack[_index].graph;
54158             },
54159             tree: function tree() {
54160               return _tree;
54161             },
54162             base: function base() {
54163               return _stack[0].graph;
54164             },
54165             merge: function merge(entities
54166             /*, extent*/
54167             ) {
54168               var stack = _stack.map(function (state) {
54169                 return state.graph;
54170               });
54171
54172               _stack[0].graph.rebase(entities, stack, false);
54173
54174               _tree.rebase(entities, false);
54175
54176               dispatch.call('merge', this, entities);
54177             },
54178             perform: function perform() {
54179               // complete any transition already in progress
54180               select(document).interrupt('history.perform');
54181               var transitionable = false;
54182               var action0 = arguments[0];
54183
54184               if (arguments.length === 1 || arguments.length === 2 && typeof arguments[1] !== 'function') {
54185                 transitionable = !!action0.transitionable;
54186               }
54187
54188               if (transitionable) {
54189                 var origArguments = arguments;
54190                 select(document).transition('history.perform').duration(duration).ease(linear$1).tween('history.tween', function () {
54191                   return function (t) {
54192                     if (t < 1) _overwrite([action0], t);
54193                   };
54194                 }).on('start', function () {
54195                   _perform([action0], 0);
54196                 }).on('end interrupt', function () {
54197                   _overwrite(origArguments, 1);
54198                 });
54199               } else {
54200                 return _perform(arguments);
54201               }
54202             },
54203             replace: function replace() {
54204               select(document).interrupt('history.perform');
54205               return _replace(arguments, 1);
54206             },
54207             // Same as calling pop and then perform
54208             overwrite: function overwrite() {
54209               select(document).interrupt('history.perform');
54210               return _overwrite(arguments, 1);
54211             },
54212             pop: function pop(n) {
54213               select(document).interrupt('history.perform');
54214               var previous = _stack[_index].graph;
54215
54216               if (isNaN(+n) || +n < 0) {
54217                 n = 1;
54218               }
54219
54220               while (n-- > 0 && _index > 0) {
54221                 _index--;
54222
54223                 _stack.pop();
54224               }
54225
54226               return change(previous);
54227             },
54228             // Back to the previous annotated state or _index = 0.
54229             undo: function undo() {
54230               select(document).interrupt('history.perform');
54231               var previousStack = _stack[_index];
54232               var previous = previousStack.graph;
54233
54234               while (_index > 0) {
54235                 _index--;
54236                 if (_stack[_index].annotation) break;
54237               }
54238
54239               dispatch.call('undone', this, _stack[_index], previousStack);
54240               return change(previous);
54241             },
54242             // Forward to the next annotated state.
54243             redo: function redo() {
54244               select(document).interrupt('history.perform');
54245               var previousStack = _stack[_index];
54246               var previous = previousStack.graph;
54247               var tryIndex = _index;
54248
54249               while (tryIndex < _stack.length - 1) {
54250                 tryIndex++;
54251
54252                 if (_stack[tryIndex].annotation) {
54253                   _index = tryIndex;
54254                   dispatch.call('redone', this, _stack[_index], previousStack);
54255                   break;
54256                 }
54257               }
54258
54259               return change(previous);
54260             },
54261             pauseChangeDispatch: function pauseChangeDispatch() {
54262               if (!_pausedGraph) {
54263                 _pausedGraph = _stack[_index].graph;
54264               }
54265             },
54266             resumeChangeDispatch: function resumeChangeDispatch() {
54267               if (_pausedGraph) {
54268                 var previous = _pausedGraph;
54269                 _pausedGraph = null;
54270                 return change(previous);
54271               }
54272             },
54273             undoAnnotation: function undoAnnotation() {
54274               var i = _index;
54275
54276               while (i >= 0) {
54277                 if (_stack[i].annotation) return _stack[i].annotation;
54278                 i--;
54279               }
54280             },
54281             redoAnnotation: function redoAnnotation() {
54282               var i = _index + 1;
54283
54284               while (i <= _stack.length - 1) {
54285                 if (_stack[i].annotation) return _stack[i].annotation;
54286                 i++;
54287               }
54288             },
54289             // Returns the entities from the active graph with bounding boxes
54290             // overlapping the given `extent`.
54291             intersects: function intersects(extent) {
54292               return _tree.intersects(extent, _stack[_index].graph);
54293             },
54294             difference: function difference() {
54295               var base = _stack[0].graph;
54296               var head = _stack[_index].graph;
54297               return coreDifference(base, head);
54298             },
54299             changes: function changes(action) {
54300               var base = _stack[0].graph;
54301               var head = _stack[_index].graph;
54302
54303               if (action) {
54304                 head = action(head);
54305               }
54306
54307               var difference = coreDifference(base, head);
54308               return {
54309                 modified: difference.modified(),
54310                 created: difference.created(),
54311                 deleted: difference.deleted()
54312               };
54313             },
54314             hasChanges: function hasChanges() {
54315               return this.difference().length() > 0;
54316             },
54317             imageryUsed: function imageryUsed(sources) {
54318               if (sources) {
54319                 _imageryUsed = sources;
54320                 return history;
54321               } else {
54322                 var s = new Set();
54323
54324                 _stack.slice(1, _index + 1).forEach(function (state) {
54325                   state.imageryUsed.forEach(function (source) {
54326                     if (source !== 'Custom') {
54327                       s.add(source);
54328                     }
54329                   });
54330                 });
54331
54332                 return Array.from(s);
54333               }
54334             },
54335             photoOverlaysUsed: function photoOverlaysUsed(sources) {
54336               if (sources) {
54337                 _photoOverlaysUsed = sources;
54338                 return history;
54339               } else {
54340                 var s = new Set();
54341
54342                 _stack.slice(1, _index + 1).forEach(function (state) {
54343                   if (state.photoOverlaysUsed && Array.isArray(state.photoOverlaysUsed)) {
54344                     state.photoOverlaysUsed.forEach(function (photoOverlay) {
54345                       s.add(photoOverlay);
54346                     });
54347                   }
54348                 });
54349
54350                 return Array.from(s);
54351               }
54352             },
54353             // save the current history state
54354             checkpoint: function checkpoint(key) {
54355               _checkpoints[key] = {
54356                 stack: _stack,
54357                 index: _index
54358               };
54359               return history;
54360             },
54361             // restore history state to a given checkpoint or reset completely
54362             reset: function reset(key) {
54363               if (key !== undefined && _checkpoints.hasOwnProperty(key)) {
54364                 _stack = _checkpoints[key].stack;
54365                 _index = _checkpoints[key].index;
54366               } else {
54367                 _stack = [{
54368                   graph: coreGraph()
54369                 }];
54370                 _index = 0;
54371                 _tree = coreTree(_stack[0].graph);
54372                 _checkpoints = {};
54373               }
54374
54375               dispatch.call('reset');
54376               dispatch.call('change');
54377               return history;
54378             },
54379             // `toIntroGraph()` is used to export the intro graph used by the walkthrough.
54380             //
54381             // To use it:
54382             //  1. Start the walkthrough.
54383             //  2. Get to a "free editing" tutorial step
54384             //  3. Make your edits to the walkthrough map
54385             //  4. In your browser dev console run:
54386             //        `id.history().toIntroGraph()`
54387             //  5. This outputs stringified JSON to the browser console
54388             //  6. Copy it to `data/intro_graph.json` and prettify it in your code editor
54389             toIntroGraph: function toIntroGraph() {
54390               var nextID = {
54391                 n: 0,
54392                 r: 0,
54393                 w: 0
54394               };
54395               var permIDs = {};
54396               var graph = this.graph();
54397               var baseEntities = {}; // clone base entities..
54398
54399               Object.values(graph.base().entities).forEach(function (entity) {
54400                 var copy = copyIntroEntity(entity);
54401                 baseEntities[copy.id] = copy;
54402               }); // replace base entities with head entities..
54403
54404               Object.keys(graph.entities).forEach(function (id) {
54405                 var entity = graph.entities[id];
54406
54407                 if (entity) {
54408                   var copy = copyIntroEntity(entity);
54409                   baseEntities[copy.id] = copy;
54410                 } else {
54411                   delete baseEntities[id];
54412                 }
54413               }); // swap temporary for permanent ids..
54414
54415               Object.values(baseEntities).forEach(function (entity) {
54416                 if (Array.isArray(entity.nodes)) {
54417                   entity.nodes = entity.nodes.map(function (node) {
54418                     return permIDs[node] || node;
54419                   });
54420                 }
54421
54422                 if (Array.isArray(entity.members)) {
54423                   entity.members = entity.members.map(function (member) {
54424                     member.id = permIDs[member.id] || member.id;
54425                     return member;
54426                   });
54427                 }
54428               });
54429               return JSON.stringify({
54430                 dataIntroGraph: baseEntities
54431               });
54432
54433               function copyIntroEntity(source) {
54434                 var copy = utilObjectOmit(source, ['type', 'user', 'v', 'version', 'visible']); // Note: the copy is no longer an osmEntity, so it might not have `tags`
54435
54436                 if (copy.tags && !Object.keys(copy.tags)) {
54437                   delete copy.tags;
54438                 }
54439
54440                 if (Array.isArray(copy.loc)) {
54441                   copy.loc[0] = +copy.loc[0].toFixed(6);
54442                   copy.loc[1] = +copy.loc[1].toFixed(6);
54443                 }
54444
54445                 var match = source.id.match(/([nrw])-\d*/); // temporary id
54446
54447                 if (match !== null) {
54448                   var nrw = match[1];
54449                   var permID;
54450
54451                   do {
54452                     permID = nrw + ++nextID[nrw];
54453                   } while (baseEntities.hasOwnProperty(permID));
54454
54455                   copy.id = permIDs[source.id] = permID;
54456                 }
54457
54458                 return copy;
54459               }
54460             },
54461             toJSON: function toJSON() {
54462               if (!this.hasChanges()) return;
54463               var allEntities = {};
54464               var baseEntities = {};
54465               var base = _stack[0];
54466
54467               var s = _stack.map(function (i) {
54468                 var modified = [];
54469                 var deleted = [];
54470                 Object.keys(i.graph.entities).forEach(function (id) {
54471                   var entity = i.graph.entities[id];
54472
54473                   if (entity) {
54474                     var key = osmEntity.key(entity);
54475                     allEntities[key] = entity;
54476                     modified.push(key);
54477                   } else {
54478                     deleted.push(id);
54479                   } // make sure that the originals of changed or deleted entities get merged
54480                   // into the base of the _stack after restoring the data from JSON.
54481
54482
54483                   if (id in base.graph.entities) {
54484                     baseEntities[id] = base.graph.entities[id];
54485                   }
54486
54487                   if (entity && entity.nodes) {
54488                     // get originals of pre-existing child nodes
54489                     entity.nodes.forEach(function (nodeID) {
54490                       if (nodeID in base.graph.entities) {
54491                         baseEntities[nodeID] = base.graph.entities[nodeID];
54492                       }
54493                     });
54494                   } // get originals of parent entities too
54495
54496
54497                   var baseParents = base.graph._parentWays[id];
54498
54499                   if (baseParents) {
54500                     baseParents.forEach(function (parentID) {
54501                       if (parentID in base.graph.entities) {
54502                         baseEntities[parentID] = base.graph.entities[parentID];
54503                       }
54504                     });
54505                   }
54506                 });
54507                 var x = {};
54508                 if (modified.length) x.modified = modified;
54509                 if (deleted.length) x.deleted = deleted;
54510                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
54511                 if (i.photoOverlaysUsed) x.photoOverlaysUsed = i.photoOverlaysUsed;
54512                 if (i.annotation) x.annotation = i.annotation;
54513                 if (i.transform) x.transform = i.transform;
54514                 if (i.selectedIDs) x.selectedIDs = i.selectedIDs;
54515                 return x;
54516               });
54517
54518               return JSON.stringify({
54519                 version: 3,
54520                 entities: Object.values(allEntities),
54521                 baseEntities: Object.values(baseEntities),
54522                 stack: s,
54523                 nextIDs: osmEntity.id.next,
54524                 index: _index,
54525                 // note the time the changes were saved
54526                 timestamp: new Date().getTime()
54527               });
54528             },
54529             fromJSON: function fromJSON(json, loadChildNodes) {
54530               var h = JSON.parse(json);
54531               var loadComplete = true;
54532               osmEntity.id.next = h.nextIDs;
54533               _index = h.index;
54534
54535               if (h.version === 2 || h.version === 3) {
54536                 var allEntities = {};
54537                 h.entities.forEach(function (entity) {
54538                   allEntities[osmEntity.key(entity)] = osmEntity(entity);
54539                 });
54540
54541                 if (h.version === 3) {
54542                   // This merges originals for changed entities into the base of
54543                   // the _stack even if the current _stack doesn't have them (for
54544                   // example when iD has been restarted in a different region)
54545                   var baseEntities = h.baseEntities.map(function (d) {
54546                     return osmEntity(d);
54547                   });
54548
54549                   var stack = _stack.map(function (state) {
54550                     return state.graph;
54551                   });
54552
54553                   _stack[0].graph.rebase(baseEntities, stack, true);
54554
54555                   _tree.rebase(baseEntities, true); // When we restore a modified way, we also need to fetch any missing
54556                   // childnodes that would normally have been downloaded with it.. #2142
54557
54558
54559                   if (loadChildNodes) {
54560                     var osm = context.connection();
54561                     var baseWays = baseEntities.filter(function (e) {
54562                       return e.type === 'way';
54563                     });
54564                     var nodeIDs = baseWays.reduce(function (acc, way) {
54565                       return utilArrayUnion(acc, way.nodes);
54566                     }, []);
54567                     var missing = nodeIDs.filter(function (n) {
54568                       return !_stack[0].graph.hasEntity(n);
54569                     });
54570
54571                     if (missing.length && osm) {
54572                       loadComplete = false;
54573                       context.map().redrawEnable(false);
54574                       var loading = uiLoading(context).blocking(true);
54575                       context.container().call(loading);
54576
54577                       var childNodesLoaded = function childNodesLoaded(err, result) {
54578                         if (!err) {
54579                           var visibleGroups = utilArrayGroupBy(result.data, 'visible');
54580                           var visibles = visibleGroups["true"] || []; // alive nodes
54581
54582                           var invisibles = visibleGroups["false"] || []; // deleted nodes
54583
54584                           if (visibles.length) {
54585                             var visibleIDs = visibles.map(function (entity) {
54586                               return entity.id;
54587                             });
54588
54589                             var stack = _stack.map(function (state) {
54590                               return state.graph;
54591                             });
54592
54593                             missing = utilArrayDifference(missing, visibleIDs);
54594
54595                             _stack[0].graph.rebase(visibles, stack, true);
54596
54597                             _tree.rebase(visibles, true);
54598                           } // fetch older versions of nodes that were deleted..
54599
54600
54601                           invisibles.forEach(function (entity) {
54602                             osm.loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
54603                           });
54604                         }
54605
54606                         if (err || !missing.length) {
54607                           loading.close();
54608                           context.map().redrawEnable(true);
54609                           dispatch.call('change');
54610                           dispatch.call('restore', this);
54611                         }
54612                       };
54613
54614                       osm.loadMultiple(missing, childNodesLoaded);
54615                     }
54616                   }
54617                 }
54618
54619                 _stack = h.stack.map(function (d) {
54620                   var entities = {},
54621                       entity;
54622
54623                   if (d.modified) {
54624                     d.modified.forEach(function (key) {
54625                       entity = allEntities[key];
54626                       entities[entity.id] = entity;
54627                     });
54628                   }
54629
54630                   if (d.deleted) {
54631                     d.deleted.forEach(function (id) {
54632                       entities[id] = undefined;
54633                     });
54634                   }
54635
54636                   return {
54637                     graph: coreGraph(_stack[0].graph).load(entities),
54638                     annotation: d.annotation,
54639                     imageryUsed: d.imageryUsed,
54640                     photoOverlaysUsed: d.photoOverlaysUsed,
54641                     transform: d.transform,
54642                     selectedIDs: d.selectedIDs
54643                   };
54644                 });
54645               } else {
54646                 // original version
54647                 _stack = h.stack.map(function (d) {
54648                   var entities = {};
54649
54650                   for (var i in d.entities) {
54651                     var entity = d.entities[i];
54652                     entities[i] = entity === 'undefined' ? undefined : osmEntity(entity);
54653                   }
54654
54655                   d.graph = coreGraph(_stack[0].graph).load(entities);
54656                   return d;
54657                 });
54658               }
54659
54660               var transform = _stack[_index].transform;
54661
54662               if (transform) {
54663                 context.map().transformEase(transform, 0); // 0 = immediate, no easing
54664               }
54665
54666               if (loadComplete) {
54667                 dispatch.call('change');
54668                 dispatch.call('restore', this);
54669               }
54670
54671               return history;
54672             },
54673             lock: function lock() {
54674               return _lock.lock();
54675             },
54676             unlock: function unlock() {
54677               _lock.unlock();
54678             },
54679             save: function save() {
54680               if (_lock.locked() && // don't overwrite existing, unresolved changes
54681               !_hasUnresolvedRestorableChanges) {
54682                 corePreferences(getKey('saved_history'), history.toJSON() || null);
54683               }
54684
54685               return history;
54686             },
54687             // delete the history version saved in localStorage
54688             clearSaved: function clearSaved() {
54689               context.debouncedSave.cancel();
54690
54691               if (_lock.locked()) {
54692                 _hasUnresolvedRestorableChanges = false;
54693                 corePreferences(getKey('saved_history'), null); // clear the changeset metadata associated with the saved history
54694
54695                 corePreferences('comment', null);
54696                 corePreferences('hashtags', null);
54697                 corePreferences('source', null);
54698               }
54699
54700               return history;
54701             },
54702             savedHistoryJSON: function savedHistoryJSON() {
54703               return corePreferences(getKey('saved_history'));
54704             },
54705             hasRestorableChanges: function hasRestorableChanges() {
54706               return _hasUnresolvedRestorableChanges;
54707             },
54708             // load history from a version stored in localStorage
54709             restore: function restore() {
54710               if (_lock.locked()) {
54711                 _hasUnresolvedRestorableChanges = false;
54712                 var json = this.savedHistoryJSON();
54713                 if (json) history.fromJSON(json, true);
54714               }
54715             },
54716             _getKey: getKey
54717           };
54718           history.reset();
54719           return utilRebind(history, dispatch, 'on');
54720         }
54721
54722         /**
54723          * Look for roads that can be connected to other roads with a short extension
54724          */
54725
54726         function validationAlmostJunction(context) {
54727           var type = 'almost_junction';
54728           var EXTEND_TH_METERS = 5;
54729           var WELD_TH_METERS = 0.75; // Comes from considering bounding case of parallel ways
54730
54731           var CLOSE_NODE_TH = EXTEND_TH_METERS - WELD_TH_METERS; // Comes from considering bounding case of perpendicular ways
54732
54733           var SIG_ANGLE_TH = Math.atan(WELD_TH_METERS / EXTEND_TH_METERS);
54734
54735           function isHighway(entity) {
54736             return entity.type === 'way' && osmRoutableHighwayTagValues[entity.tags.highway];
54737           }
54738
54739           function isTaggedAsNotContinuing(node) {
54740             return node.tags.noexit === 'yes' || node.tags.amenity === 'parking_entrance' || node.tags.entrance && node.tags.entrance !== 'no';
54741           }
54742
54743           var validation = function checkAlmostJunction(entity, graph) {
54744             if (!isHighway(entity)) return [];
54745             if (entity.isDegenerate()) return [];
54746             var tree = context.history().tree();
54747             var extendableNodeInfos = findConnectableEndNodesByExtension(entity);
54748             var issues = [];
54749             extendableNodeInfos.forEach(function (extendableNodeInfo) {
54750               issues.push(new validationIssue({
54751                 type: type,
54752                 subtype: 'highway-highway',
54753                 severity: 'warning',
54754                 message: function message(context) {
54755                   var entity1 = context.hasEntity(this.entityIds[0]);
54756
54757                   if (this.entityIds[0] === this.entityIds[2]) {
54758                     return entity1 ? _t.html('issues.almost_junction.self.message', {
54759                       feature: utilDisplayLabel(entity1, context.graph())
54760                     }) : '';
54761                   } else {
54762                     var entity2 = context.hasEntity(this.entityIds[2]);
54763                     return entity1 && entity2 ? _t.html('issues.almost_junction.message', {
54764                       feature: utilDisplayLabel(entity1, context.graph()),
54765                       feature2: utilDisplayLabel(entity2, context.graph())
54766                     }) : '';
54767                   }
54768                 },
54769                 reference: showReference,
54770                 entityIds: [entity.id, extendableNodeInfo.node.id, extendableNodeInfo.wid],
54771                 loc: extendableNodeInfo.node.loc,
54772                 hash: JSON.stringify(extendableNodeInfo.node.loc),
54773                 data: {
54774                   midId: extendableNodeInfo.mid.id,
54775                   edge: extendableNodeInfo.edge,
54776                   cross_loc: extendableNodeInfo.cross_loc
54777                 },
54778                 dynamicFixes: makeFixes
54779               }));
54780             });
54781             return issues;
54782
54783             function makeFixes(context) {
54784               var fixes = [new validationIssueFix({
54785                 icon: 'iD-icon-abutment',
54786                 title: _t.html('issues.fix.connect_features.title'),
54787                 onClick: function onClick(context) {
54788                   var annotation = _t('issues.fix.connect_almost_junction.annotation');
54789
54790                   var _this$issue$entityIds = _slicedToArray(this.issue.entityIds, 3),
54791                       endNodeId = _this$issue$entityIds[1],
54792                       crossWayId = _this$issue$entityIds[2];
54793
54794                   var midNode = context.entity(this.issue.data.midId);
54795                   var endNode = context.entity(endNodeId);
54796                   var crossWay = context.entity(crossWayId); // When endpoints are close, just join if resulting small change in angle (#7201)
54797
54798                   var nearEndNodes = findNearbyEndNodes(endNode, crossWay);
54799
54800                   if (nearEndNodes.length > 0) {
54801                     var collinear = findSmallJoinAngle(midNode, endNode, nearEndNodes);
54802
54803                     if (collinear) {
54804                       context.perform(actionMergeNodes([collinear.id, endNode.id], collinear.loc), annotation);
54805                       return;
54806                     }
54807                   }
54808
54809                   var targetEdge = this.issue.data.edge;
54810                   var crossLoc = this.issue.data.cross_loc;
54811                   var edgeNodes = [context.entity(targetEdge[0]), context.entity(targetEdge[1])];
54812                   var closestNodeInfo = geoSphericalClosestNode(edgeNodes, crossLoc); // already a point nearby, just connect to that
54813
54814                   if (closestNodeInfo.distance < WELD_TH_METERS) {
54815                     context.perform(actionMergeNodes([closestNodeInfo.node.id, endNode.id], closestNodeInfo.node.loc), annotation); // else add the end node to the edge way
54816                   } else {
54817                     context.perform(actionAddMidpoint({
54818                       loc: crossLoc,
54819                       edge: targetEdge
54820                     }, endNode), annotation);
54821                   }
54822                 }
54823               })];
54824               var node = context.hasEntity(this.entityIds[1]);
54825
54826               if (node && !node.hasInterestingTags()) {
54827                 // node has no descriptive tags, suggest noexit fix
54828                 fixes.push(new validationIssueFix({
54829                   icon: 'maki-barrier',
54830                   title: _t.html('issues.fix.tag_as_disconnected.title'),
54831                   onClick: function onClick(context) {
54832                     var nodeID = this.issue.entityIds[1];
54833                     var tags = Object.assign({}, context.entity(nodeID).tags);
54834                     tags.noexit = 'yes';
54835                     context.perform(actionChangeTags(nodeID, tags), _t('issues.fix.tag_as_disconnected.annotation'));
54836                   }
54837                 }));
54838               }
54839
54840               return fixes;
54841             }
54842
54843             function showReference(selection) {
54844               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.almost_junction.highway-highway.reference'));
54845             }
54846
54847             function isExtendableCandidate(node, way) {
54848               // can not accurately test vertices on tiles not downloaded from osm - #5938
54849               var osm = services.osm;
54850
54851               if (osm && !osm.isDataLoaded(node.loc)) {
54852                 return false;
54853               }
54854
54855               if (isTaggedAsNotContinuing(node) || graph.parentWays(node).length !== 1) {
54856                 return false;
54857               }
54858
54859               var occurrences = 0;
54860
54861               for (var index in way.nodes) {
54862                 if (way.nodes[index] === node.id) {
54863                   occurrences += 1;
54864
54865                   if (occurrences > 1) {
54866                     return false;
54867                   }
54868                 }
54869               }
54870
54871               return true;
54872             }
54873
54874             function findConnectableEndNodesByExtension(way) {
54875               var results = [];
54876               if (way.isClosed()) return results;
54877               var testNodes;
54878               var indices = [0, way.nodes.length - 1];
54879               indices.forEach(function (nodeIndex) {
54880                 var nodeID = way.nodes[nodeIndex];
54881                 var node = graph.entity(nodeID);
54882                 if (!isExtendableCandidate(node, way)) return;
54883                 var connectionInfo = canConnectByExtend(way, nodeIndex);
54884                 if (!connectionInfo) return;
54885                 testNodes = graph.childNodes(way).slice(); // shallow copy
54886
54887                 testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc); // don't flag issue if connecting the ways would cause self-intersection
54888
54889                 if (geoHasSelfIntersections(testNodes, nodeID)) return;
54890                 results.push(connectionInfo);
54891               });
54892               return results;
54893             }
54894
54895             function findNearbyEndNodes(node, way) {
54896               return [way.nodes[0], way.nodes[way.nodes.length - 1]].map(function (d) {
54897                 return graph.entity(d);
54898               }).filter(function (d) {
54899                 // Node cannot be near to itself, but other endnode of same way could be
54900                 return d.id !== node.id && geoSphericalDistance(node.loc, d.loc) <= CLOSE_NODE_TH;
54901               });
54902             }
54903
54904             function findSmallJoinAngle(midNode, tipNode, endNodes) {
54905               // Both nodes could be close, so want to join whichever is closest to collinear
54906               var joinTo;
54907               var minAngle = Infinity; // Checks midNode -> tipNode -> endNode for collinearity
54908
54909               endNodes.forEach(function (endNode) {
54910                 var a1 = geoAngle(midNode, tipNode, context.projection) + Math.PI;
54911                 var a2 = geoAngle(midNode, endNode, context.projection) + Math.PI;
54912                 var diff = Math.max(a1, a2) - Math.min(a1, a2);
54913
54914                 if (diff < minAngle) {
54915                   joinTo = endNode;
54916                   minAngle = diff;
54917                 }
54918               });
54919               /* Threshold set by considering right angle triangle
54920               based on node joining threshold and extension distance */
54921
54922               if (minAngle <= SIG_ANGLE_TH) return joinTo;
54923               return null;
54924             }
54925
54926             function hasTag(tags, key) {
54927               return tags[key] !== undefined && tags[key] !== 'no';
54928             }
54929
54930             function canConnectWays(way, way2) {
54931               // allow self-connections
54932               if (way.id === way2.id) return true; // if one is bridge or tunnel, both must be bridge or tunnel
54933
54934               if ((hasTag(way.tags, 'bridge') || hasTag(way2.tags, 'bridge')) && !(hasTag(way.tags, 'bridge') && hasTag(way2.tags, 'bridge'))) return false;
54935               if ((hasTag(way.tags, 'tunnel') || hasTag(way2.tags, 'tunnel')) && !(hasTag(way.tags, 'tunnel') && hasTag(way2.tags, 'tunnel'))) return false; // must have equivalent layers and levels
54936
54937               var layer1 = way.tags.layer || '0',
54938                   layer2 = way2.tags.layer || '0';
54939               if (layer1 !== layer2) return false;
54940               var level1 = way.tags.level || '0',
54941                   level2 = way2.tags.level || '0';
54942               if (level1 !== level2) return false;
54943               return true;
54944             }
54945
54946             function canConnectByExtend(way, endNodeIdx) {
54947               var tipNid = way.nodes[endNodeIdx]; // the 'tip' node for extension point
54948
54949               var midNid = endNodeIdx === 0 ? way.nodes[1] : way.nodes[way.nodes.length - 2]; // the other node of the edge
54950
54951               var tipNode = graph.entity(tipNid);
54952               var midNode = graph.entity(midNid);
54953               var lon = tipNode.loc[0];
54954               var lat = tipNode.loc[1];
54955               var lon_range = geoMetersToLon(EXTEND_TH_METERS, lat) / 2;
54956               var lat_range = geoMetersToLat(EXTEND_TH_METERS) / 2;
54957               var queryExtent = geoExtent([[lon - lon_range, lat - lat_range], [lon + lon_range, lat + lat_range]]); // first, extend the edge of [midNode -> tipNode] by EXTEND_TH_METERS and find the "extended tip" location
54958
54959               var edgeLen = geoSphericalDistance(midNode.loc, tipNode.loc);
54960               var t = EXTEND_TH_METERS / edgeLen + 1.0;
54961               var extTipLoc = geoVecInterp(midNode.loc, tipNode.loc, t); // then, check if the extension part [tipNode.loc -> extTipLoc] intersects any other ways
54962
54963               var segmentInfos = tree.waySegments(queryExtent, graph);
54964
54965               for (var i = 0; i < segmentInfos.length; i++) {
54966                 var segmentInfo = segmentInfos[i];
54967                 var way2 = graph.entity(segmentInfo.wayId);
54968                 if (!isHighway(way2)) continue;
54969                 if (!canConnectWays(way, way2)) continue;
54970                 var nAid = segmentInfo.nodes[0],
54971                     nBid = segmentInfo.nodes[1];
54972                 if (nAid === tipNid || nBid === tipNid) continue;
54973                 var nA = graph.entity(nAid),
54974                     nB = graph.entity(nBid);
54975                 var crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
54976
54977                 if (crossLoc) {
54978                   return {
54979                     mid: midNode,
54980                     node: tipNode,
54981                     wid: way2.id,
54982                     edge: [nA.id, nB.id],
54983                     cross_loc: crossLoc
54984                   };
54985                 }
54986               }
54987
54988               return null;
54989             }
54990           };
54991
54992           validation.type = type;
54993           return validation;
54994         }
54995
54996         function validationCloseNodes(context) {
54997           var type = 'close_nodes';
54998           var pointThresholdMeters = 0.2;
54999
55000           var validation = function validation(entity, graph) {
55001             if (entity.type === 'node') {
55002               return getIssuesForNode(entity);
55003             } else if (entity.type === 'way') {
55004               return getIssuesForWay(entity);
55005             }
55006
55007             return [];
55008
55009             function getIssuesForNode(node) {
55010               var parentWays = graph.parentWays(node);
55011
55012               if (parentWays.length) {
55013                 return getIssuesForVertex(node, parentWays);
55014               } else {
55015                 return getIssuesForDetachedPoint(node);
55016               }
55017             }
55018
55019             function wayTypeFor(way) {
55020               if (way.tags.boundary && way.tags.boundary !== 'no') return 'boundary';
55021               if (way.tags.indoor && way.tags.indoor !== 'no') return 'indoor';
55022               if (way.tags.building && way.tags.building !== 'no' || way.tags['building:part'] && way.tags['building:part'] !== 'no') return 'building';
55023               if (osmPathHighwayTagValues[way.tags.highway]) return 'path';
55024               var parentRelations = graph.parentRelations(way);
55025
55026               for (var i in parentRelations) {
55027                 var relation = parentRelations[i];
55028                 if (relation.tags.type === 'boundary') return 'boundary';
55029
55030                 if (relation.isMultipolygon()) {
55031                   if (relation.tags.indoor && relation.tags.indoor !== 'no') return 'indoor';
55032                   if (relation.tags.building && relation.tags.building !== 'no' || relation.tags['building:part'] && relation.tags['building:part'] !== 'no') return 'building';
55033                 }
55034               }
55035
55036               return 'other';
55037             }
55038
55039             function shouldCheckWay(way) {
55040               // don't flag issues where merging would create degenerate ways
55041               if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4) return false;
55042               var bbox = way.extent(graph).bbox();
55043               var hypotenuseMeters = geoSphericalDistance([bbox.minX, bbox.minY], [bbox.maxX, bbox.maxY]); // don't flag close nodes in very small ways
55044
55045               if (hypotenuseMeters < 1.5) return false;
55046               return true;
55047             }
55048
55049             function getIssuesForWay(way) {
55050               if (!shouldCheckWay(way)) return [];
55051               var issues = [],
55052                   nodes = graph.childNodes(way);
55053
55054               for (var i = 0; i < nodes.length - 1; i++) {
55055                 var node1 = nodes[i];
55056                 var node2 = nodes[i + 1];
55057                 var issue = getWayIssueIfAny(node1, node2, way);
55058                 if (issue) issues.push(issue);
55059               }
55060
55061               return issues;
55062             }
55063
55064             function getIssuesForVertex(node, parentWays) {
55065               var issues = [];
55066
55067               function checkForCloseness(node1, node2, way) {
55068                 var issue = getWayIssueIfAny(node1, node2, way);
55069                 if (issue) issues.push(issue);
55070               }
55071
55072               for (var i = 0; i < parentWays.length; i++) {
55073                 var parentWay = parentWays[i];
55074                 if (!shouldCheckWay(parentWay)) continue;
55075                 var lastIndex = parentWay.nodes.length - 1;
55076
55077                 for (var j = 0; j < parentWay.nodes.length; j++) {
55078                   if (j !== 0) {
55079                     if (parentWay.nodes[j - 1] === node.id) {
55080                       checkForCloseness(node, graph.entity(parentWay.nodes[j]), parentWay);
55081                     }
55082                   }
55083
55084                   if (j !== lastIndex) {
55085                     if (parentWay.nodes[j + 1] === node.id) {
55086                       checkForCloseness(graph.entity(parentWay.nodes[j]), node, parentWay);
55087                     }
55088                   }
55089                 }
55090               }
55091
55092               return issues;
55093             }
55094
55095             function thresholdMetersForWay(way) {
55096               if (!shouldCheckWay(way)) return 0;
55097               var wayType = wayTypeFor(way); // don't flag boundaries since they might be highly detailed and can't be easily verified
55098
55099               if (wayType === 'boundary') return 0; // expect some features to be mapped with higher levels of detail
55100
55101               if (wayType === 'indoor') return 0.01;
55102               if (wayType === 'building') return 0.05;
55103               if (wayType === 'path') return 0.1;
55104               return 0.2;
55105             }
55106
55107             function getIssuesForDetachedPoint(node) {
55108               var issues = [];
55109               var lon = node.loc[0];
55110               var lat = node.loc[1];
55111               var lon_range = geoMetersToLon(pointThresholdMeters, lat) / 2;
55112               var lat_range = geoMetersToLat(pointThresholdMeters) / 2;
55113               var queryExtent = geoExtent([[lon - lon_range, lat - lat_range], [lon + lon_range, lat + lat_range]]);
55114               var intersected = context.history().tree().intersects(queryExtent, graph);
55115
55116               for (var j = 0; j < intersected.length; j++) {
55117                 var nearby = intersected[j];
55118                 if (nearby.id === node.id) continue;
55119                 if (nearby.type !== 'node' || nearby.geometry(graph) !== 'point') continue;
55120
55121                 if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
55122                   // allow very close points if tags indicate the z-axis might vary
55123                   var zAxisKeys = {
55124                     layer: true,
55125                     level: true,
55126                     'addr:housenumber': true,
55127                     'addr:unit': true
55128                   };
55129                   var zAxisDifferentiates = false;
55130
55131                   for (var key in zAxisKeys) {
55132                     var nodeValue = node.tags[key] || '0';
55133                     var nearbyValue = nearby.tags[key] || '0';
55134
55135                     if (nodeValue !== nearbyValue) {
55136                       zAxisDifferentiates = true;
55137                       break;
55138                     }
55139                   }
55140
55141                   if (zAxisDifferentiates) continue;
55142                   issues.push(new validationIssue({
55143                     type: type,
55144                     subtype: 'detached',
55145                     severity: 'warning',
55146                     message: function message(context) {
55147                       var entity = context.hasEntity(this.entityIds[0]),
55148                           entity2 = context.hasEntity(this.entityIds[1]);
55149                       return entity && entity2 ? _t.html('issues.close_nodes.detached.message', {
55150                         feature: utilDisplayLabel(entity, context.graph()),
55151                         feature2: utilDisplayLabel(entity2, context.graph())
55152                       }) : '';
55153                     },
55154                     reference: showReference,
55155                     entityIds: [node.id, nearby.id],
55156                     dynamicFixes: function dynamicFixes() {
55157                       return [new validationIssueFix({
55158                         icon: 'iD-operation-disconnect',
55159                         title: _t.html('issues.fix.move_points_apart.title')
55160                       }), new validationIssueFix({
55161                         icon: 'iD-icon-layers',
55162                         title: _t.html('issues.fix.use_different_layers_or_levels.title')
55163                       })];
55164                     }
55165                   }));
55166                 }
55167               }
55168
55169               return issues;
55170
55171               function showReference(selection) {
55172                 var referenceText = _t('issues.close_nodes.detached.reference');
55173                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
55174               }
55175             }
55176
55177             function getWayIssueIfAny(node1, node2, way) {
55178               if (node1.id === node2.id || node1.hasInterestingTags() && node2.hasInterestingTags()) {
55179                 return null;
55180               }
55181
55182               if (node1.loc !== node2.loc) {
55183                 var parentWays1 = graph.parentWays(node1);
55184                 var parentWays2 = new Set(graph.parentWays(node2));
55185                 var sharedWays = parentWays1.filter(function (parentWay) {
55186                   return parentWays2.has(parentWay);
55187                 });
55188                 var thresholds = sharedWays.map(function (parentWay) {
55189                   return thresholdMetersForWay(parentWay);
55190                 });
55191                 var threshold = Math.min.apply(Math, _toConsumableArray(thresholds));
55192                 var distance = geoSphericalDistance(node1.loc, node2.loc);
55193                 if (distance > threshold) return null;
55194               }
55195
55196               return new validationIssue({
55197                 type: type,
55198                 subtype: 'vertices',
55199                 severity: 'warning',
55200                 message: function message(context) {
55201                   var entity = context.hasEntity(this.entityIds[0]);
55202                   return entity ? _t.html('issues.close_nodes.message', {
55203                     way: utilDisplayLabel(entity, context.graph())
55204                   }) : '';
55205                 },
55206                 reference: showReference,
55207                 entityIds: [way.id, node1.id, node2.id],
55208                 loc: node1.loc,
55209                 dynamicFixes: function dynamicFixes() {
55210                   return [new validationIssueFix({
55211                     icon: 'iD-icon-plus',
55212                     title: _t.html('issues.fix.merge_points.title'),
55213                     onClick: function onClick(context) {
55214                       var entityIds = this.issue.entityIds;
55215                       var action = actionMergeNodes([entityIds[1], entityIds[2]]);
55216                       context.perform(action, _t('issues.fix.merge_close_vertices.annotation'));
55217                     }
55218                   }), new validationIssueFix({
55219                     icon: 'iD-operation-disconnect',
55220                     title: _t.html('issues.fix.move_points_apart.title')
55221                   })];
55222                 }
55223               });
55224
55225               function showReference(selection) {
55226                 var referenceText = _t('issues.close_nodes.reference');
55227                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
55228               }
55229             }
55230           };
55231
55232           validation.type = type;
55233           return validation;
55234         }
55235
55236         function validationCrossingWays(context) {
55237           var type = 'crossing_ways'; // returns the way or its parent relation, whichever has a useful feature type
55238
55239           function getFeatureWithFeatureTypeTagsForWay(way, graph) {
55240             if (getFeatureType(way, graph) === null) {
55241               // if the way doesn't match a feature type, check its parent relations
55242               var parentRels = graph.parentRelations(way);
55243
55244               for (var i = 0; i < parentRels.length; i++) {
55245                 var rel = parentRels[i];
55246
55247                 if (getFeatureType(rel, graph) !== null) {
55248                   return rel;
55249                 }
55250               }
55251             }
55252
55253             return way;
55254           }
55255
55256           function hasTag(tags, key) {
55257             return tags[key] !== undefined && tags[key] !== 'no';
55258           }
55259
55260           function taggedAsIndoor(tags) {
55261             return hasTag(tags, 'indoor') || hasTag(tags, 'level') || tags.highway === 'corridor';
55262           }
55263
55264           function allowsBridge(featureType) {
55265             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
55266           }
55267
55268           function allowsTunnel(featureType) {
55269             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
55270           } // discard
55271
55272
55273           var ignoredBuildings = {
55274             demolished: true,
55275             dismantled: true,
55276             proposed: true,
55277             razed: true
55278           };
55279
55280           function getFeatureType(entity, graph) {
55281             var geometry = entity.geometry(graph);
55282             if (geometry !== 'line' && geometry !== 'area') return null;
55283             var tags = entity.tags;
55284             if (hasTag(tags, 'building') && !ignoredBuildings[tags.building]) return 'building';
55285             if (hasTag(tags, 'highway') && osmRoutableHighwayTagValues[tags.highway]) return 'highway'; // don't check railway or waterway areas
55286
55287             if (geometry !== 'line') return null;
55288             if (hasTag(tags, 'railway') && osmRailwayTrackTagValues[tags.railway]) return 'railway';
55289             if (hasTag(tags, 'waterway') && osmFlowingWaterwayTagValues[tags.waterway]) return 'waterway';
55290             return null;
55291           }
55292
55293           function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
55294             // assume 0 by default
55295             var level1 = tags1.level || '0';
55296             var level2 = tags2.level || '0';
55297
55298             if (taggedAsIndoor(tags1) && taggedAsIndoor(tags2) && level1 !== level2) {
55299               // assume features don't interact if they're indoor on different levels
55300               return true;
55301             } // assume 0 by default; don't use way.layer() since we account for structures here
55302
55303
55304             var layer1 = tags1.layer || '0';
55305             var layer2 = tags2.layer || '0';
55306
55307             if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
55308               if (hasTag(tags1, 'bridge') && !hasTag(tags2, 'bridge')) return true;
55309               if (!hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge')) return true; // crossing bridges must use different layers
55310
55311               if (hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge') && layer1 !== layer2) return true;
55312             } else if (allowsBridge(featureType1) && hasTag(tags1, 'bridge')) return true;else if (allowsBridge(featureType2) && hasTag(tags2, 'bridge')) return true;
55313
55314             if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
55315               if (hasTag(tags1, 'tunnel') && !hasTag(tags2, 'tunnel')) return true;
55316               if (!hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel')) return true; // crossing tunnels must use different layers
55317
55318               if (hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel') && layer1 !== layer2) return true;
55319             } else if (allowsTunnel(featureType1) && hasTag(tags1, 'tunnel')) return true;else if (allowsTunnel(featureType2) && hasTag(tags2, 'tunnel')) return true; // don't flag crossing waterways and pier/highways
55320
55321
55322             if (featureType1 === 'waterway' && featureType2 === 'highway' && tags2.man_made === 'pier') return true;
55323             if (featureType2 === 'waterway' && featureType1 === 'highway' && tags1.man_made === 'pier') return true;
55324
55325             if (featureType1 === 'building' || featureType2 === 'building') {
55326               // for building crossings, different layers are enough
55327               if (layer1 !== layer2) return true;
55328             }
55329
55330             return false;
55331           } // highway values for which we shouldn't recommend connecting to waterways
55332
55333
55334           var highwaysDisallowingFords = {
55335             motorway: true,
55336             motorway_link: true,
55337             trunk: true,
55338             trunk_link: true,
55339             primary: true,
55340             primary_link: true,
55341             secondary: true,
55342             secondary_link: true
55343           };
55344           var nonCrossingHighways = {
55345             track: true
55346           };
55347
55348           function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
55349             var featureType1 = getFeatureType(entity1, graph);
55350             var featureType2 = getFeatureType(entity2, graph);
55351             var geometry1 = entity1.geometry(graph);
55352             var geometry2 = entity2.geometry(graph);
55353             var bothLines = geometry1 === 'line' && geometry2 === 'line';
55354
55355             if (featureType1 === featureType2) {
55356               if (featureType1 === 'highway') {
55357                 var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
55358                 var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
55359
55360                 if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
55361                   // one feature is a path but not both
55362                   var roadFeature = entity1IsPath ? entity2 : entity1;
55363
55364                   if (nonCrossingHighways[roadFeature.tags.highway]) {
55365                     // don't mark path connections with certain roads as crossings
55366                     return {};
55367                   }
55368
55369                   var pathFeature = entity1IsPath ? entity1 : entity2;
55370
55371                   if (['marked', 'unmarked'].indexOf(pathFeature.tags.crossing) !== -1) {
55372                     // if the path is a crossing, match the crossing type
55373                     return bothLines ? {
55374                       highway: 'crossing',
55375                       crossing: pathFeature.tags.crossing
55376                     } : {};
55377                   } // don't add a `crossing` subtag to ambiguous crossings
55378
55379
55380                   return bothLines ? {
55381                     highway: 'crossing'
55382                   } : {};
55383                 }
55384
55385                 return {};
55386               }
55387
55388               if (featureType1 === 'waterway') return {};
55389               if (featureType1 === 'railway') return {};
55390             } else {
55391               var featureTypes = [featureType1, featureType2];
55392
55393               if (featureTypes.indexOf('highway') !== -1) {
55394                 if (featureTypes.indexOf('railway') !== -1) {
55395                   if (!bothLines) return {};
55396                   var isTram = entity1.tags.railway === 'tram' || entity2.tags.railway === 'tram';
55397
55398                   if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
55399                     // path-tram connections use this tag
55400                     if (isTram) return {
55401                       railway: 'tram_crossing'
55402                     }; // other path-rail connections use this tag
55403
55404                     return {
55405                       railway: 'crossing'
55406                     };
55407                   } else {
55408                     // path-tram connections use this tag
55409                     if (isTram) return {
55410                       railway: 'tram_level_crossing'
55411                     }; // other road-rail connections use this tag
55412
55413                     return {
55414                       railway: 'level_crossing'
55415                     };
55416                   }
55417                 }
55418
55419                 if (featureTypes.indexOf('waterway') !== -1) {
55420                   // do not allow fords on structures
55421                   if (hasTag(entity1.tags, 'tunnel') && hasTag(entity2.tags, 'tunnel')) return null;
55422                   if (hasTag(entity1.tags, 'bridge') && hasTag(entity2.tags, 'bridge')) return null;
55423
55424                   if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
55425                     // do not allow fords on major highways
55426                     return null;
55427                   }
55428
55429                   return bothLines ? {
55430                     ford: 'yes'
55431                   } : {};
55432                 }
55433               }
55434             }
55435
55436             return null;
55437           }
55438
55439           function findCrossingsByWay(way1, graph, tree) {
55440             var edgeCrossInfos = [];
55441             if (way1.type !== 'way') return edgeCrossInfos;
55442             var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
55443             var way1FeatureType = getFeatureType(taggedFeature1, graph);
55444             if (way1FeatureType === null) return edgeCrossInfos;
55445             var checkedSingleCrossingWays = {}; // declare vars ahead of time to reduce garbage collection
55446
55447             var i, j;
55448             var extent;
55449             var n1, n2, nA, nB, nAId, nBId;
55450             var segment1, segment2;
55451             var oneOnly;
55452             var segmentInfos, segment2Info, way2, taggedFeature2, way2FeatureType;
55453             var way1Nodes = graph.childNodes(way1);
55454             var comparedWays = {};
55455
55456             for (i = 0; i < way1Nodes.length - 1; i++) {
55457               n1 = way1Nodes[i];
55458               n2 = way1Nodes[i + 1];
55459               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])]]); // Optimize by only checking overlapping segments, not every segment
55460               // of overlapping ways
55461
55462               segmentInfos = tree.waySegments(extent, graph);
55463
55464               for (j = 0; j < segmentInfos.length; j++) {
55465                 segment2Info = segmentInfos[j]; // don't check for self-intersection in this validation
55466
55467                 if (segment2Info.wayId === way1.id) continue; // skip if this way was already checked and only one issue is needed
55468
55469                 if (checkedSingleCrossingWays[segment2Info.wayId]) continue; // mark this way as checked even if there are no crossings
55470
55471                 comparedWays[segment2Info.wayId] = true;
55472                 way2 = graph.hasEntity(segment2Info.wayId);
55473                 if (!way2) continue;
55474                 taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph); // only check crossing highway, waterway, building, and railway
55475
55476                 way2FeatureType = getFeatureType(taggedFeature2, graph);
55477
55478                 if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
55479                   continue;
55480                 } // create only one issue for building crossings
55481
55482
55483                 oneOnly = way1FeatureType === 'building' || way2FeatureType === 'building';
55484                 nAId = segment2Info.nodes[0];
55485                 nBId = segment2Info.nodes[1];
55486
55487                 if (nAId === n1.id || nAId === n2.id || nBId === n1.id || nBId === n2.id) {
55488                   // n1 or n2 is a connection node; skip
55489                   continue;
55490                 }
55491
55492                 nA = graph.hasEntity(nAId);
55493                 if (!nA) continue;
55494                 nB = graph.hasEntity(nBId);
55495                 if (!nB) continue;
55496                 segment1 = [n1.loc, n2.loc];
55497                 segment2 = [nA.loc, nB.loc];
55498                 var point = geoLineIntersection(segment1, segment2);
55499
55500                 if (point) {
55501                   edgeCrossInfos.push({
55502                     wayInfos: [{
55503                       way: way1,
55504                       featureType: way1FeatureType,
55505                       edge: [n1.id, n2.id]
55506                     }, {
55507                       way: way2,
55508                       featureType: way2FeatureType,
55509                       edge: [nA.id, nB.id]
55510                     }],
55511                     crossPoint: point
55512                   });
55513
55514                   if (oneOnly) {
55515                     checkedSingleCrossingWays[way2.id] = true;
55516                     break;
55517                   }
55518                 }
55519               }
55520             }
55521
55522             return edgeCrossInfos;
55523           }
55524
55525           function waysToCheck(entity, graph) {
55526             var featureType = getFeatureType(entity, graph);
55527             if (!featureType) return [];
55528
55529             if (entity.type === 'way') {
55530               return [entity];
55531             } else if (entity.type === 'relation') {
55532               return entity.members.reduce(function (array, member) {
55533                 if (member.type === 'way' && ( // only look at geometry ways
55534                 !member.role || member.role === 'outer' || member.role === 'inner')) {
55535                   var entity = graph.hasEntity(member.id); // don't add duplicates
55536
55537                   if (entity && array.indexOf(entity) === -1) {
55538                     array.push(entity);
55539                   }
55540                 }
55541
55542                 return array;
55543               }, []);
55544             }
55545
55546             return [];
55547           }
55548
55549           var validation = function checkCrossingWays(entity, graph) {
55550             var tree = context.history().tree();
55551             var ways = waysToCheck(entity, graph);
55552             var issues = []; // declare these here to reduce garbage collection
55553
55554             var wayIndex, crossingIndex, crossings;
55555
55556             for (wayIndex in ways) {
55557               crossings = findCrossingsByWay(ways[wayIndex], graph, tree);
55558
55559               for (crossingIndex in crossings) {
55560                 issues.push(createIssue(crossings[crossingIndex], graph));
55561               }
55562             }
55563
55564             return issues;
55565           };
55566
55567           function createIssue(crossing, graph) {
55568             // use the entities with the tags that define the feature type
55569             crossing.wayInfos.sort(function (way1Info, way2Info) {
55570               var type1 = way1Info.featureType;
55571               var type2 = way2Info.featureType;
55572
55573               if (type1 === type2) {
55574                 return utilDisplayLabel(way1Info.way, graph) > utilDisplayLabel(way2Info.way, graph);
55575               } else if (type1 === 'waterway') {
55576                 return true;
55577               } else if (type2 === 'waterway') {
55578                 return false;
55579               }
55580
55581               return type1 < type2;
55582             });
55583             var entities = crossing.wayInfos.map(function (wayInfo) {
55584               return getFeatureWithFeatureTypeTagsForWay(wayInfo.way, graph);
55585             });
55586             var edges = [crossing.wayInfos[0].edge, crossing.wayInfos[1].edge];
55587             var featureTypes = [crossing.wayInfos[0].featureType, crossing.wayInfos[1].featureType];
55588             var connectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph);
55589             var featureType1 = crossing.wayInfos[0].featureType;
55590             var featureType2 = crossing.wayInfos[1].featureType;
55591             var isCrossingIndoors = taggedAsIndoor(entities[0].tags) && taggedAsIndoor(entities[1].tags);
55592             var isCrossingTunnels = allowsTunnel(featureType1) && hasTag(entities[0].tags, 'tunnel') && allowsTunnel(featureType2) && hasTag(entities[1].tags, 'tunnel');
55593             var isCrossingBridges = allowsBridge(featureType1) && hasTag(entities[0].tags, 'bridge') && allowsBridge(featureType2) && hasTag(entities[1].tags, 'bridge');
55594             var subtype = [featureType1, featureType2].sort().join('-');
55595             var crossingTypeID = subtype;
55596
55597             if (isCrossingIndoors) {
55598               crossingTypeID = 'indoor-indoor';
55599             } else if (isCrossingTunnels) {
55600               crossingTypeID = 'tunnel-tunnel';
55601             } else if (isCrossingBridges) {
55602               crossingTypeID = 'bridge-bridge';
55603             }
55604
55605             if (connectionTags && (isCrossingIndoors || isCrossingTunnels || isCrossingBridges)) {
55606               crossingTypeID += '_connectable';
55607             }
55608
55609             return new validationIssue({
55610               type: type,
55611               subtype: subtype,
55612               severity: 'warning',
55613               message: function message(context) {
55614                 var graph = context.graph();
55615                 var entity1 = graph.hasEntity(this.entityIds[0]),
55616                     entity2 = graph.hasEntity(this.entityIds[1]);
55617                 return entity1 && entity2 ? _t.html('issues.crossing_ways.message', {
55618                   feature: utilDisplayLabel(entity1, graph),
55619                   feature2: utilDisplayLabel(entity2, graph)
55620                 }) : '';
55621               },
55622               reference: showReference,
55623               entityIds: entities.map(function (entity) {
55624                 return entity.id;
55625               }),
55626               data: {
55627                 edges: edges,
55628                 featureTypes: featureTypes,
55629                 connectionTags: connectionTags
55630               },
55631               // differentiate based on the loc since two ways can cross multiple times
55632               hash: crossing.crossPoint.toString() + // if the edges change then so does the fix
55633               edges.slice().sort(function (edge1, edge2) {
55634                 // order to assure hash is deterministic
55635                 return edge1[0] < edge2[0] ? -1 : 1;
55636               }).toString() + // ensure the correct connection tags are added in the fix
55637               JSON.stringify(connectionTags),
55638               loc: crossing.crossPoint,
55639               dynamicFixes: function dynamicFixes(context) {
55640                 var mode = context.mode();
55641                 if (!mode || mode.id !== 'select' || mode.selectedIDs().length !== 1) return [];
55642                 var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
55643                 var selectedFeatureType = this.data.featureTypes[selectedIndex];
55644                 var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
55645                 var fixes = [];
55646
55647                 if (connectionTags) {
55648                   fixes.push(makeConnectWaysFix(this.data.connectionTags));
55649                 }
55650
55651                 if (isCrossingIndoors) {
55652                   fixes.push(new validationIssueFix({
55653                     icon: 'iD-icon-layers',
55654                     title: _t.html('issues.fix.use_different_levels.title')
55655                   }));
55656                 } else if (isCrossingTunnels || isCrossingBridges || featureType1 === 'building' || featureType2 === 'building') {
55657                   fixes.push(makeChangeLayerFix('higher'));
55658                   fixes.push(makeChangeLayerFix('lower')); // can only add bridge/tunnel if both features are lines
55659                 } else if (context.graph().geometry(this.entityIds[0]) === 'line' && context.graph().geometry(this.entityIds[1]) === 'line') {
55660                   // don't recommend adding bridges to waterways since they're uncommon
55661                   if (allowsBridge(selectedFeatureType) && selectedFeatureType !== 'waterway') {
55662                     fixes.push(makeAddBridgeOrTunnelFix('add_a_bridge', 'temaki-bridge', 'bridge'));
55663                   } // don't recommend adding tunnels under waterways since they're uncommon
55664
55665
55666                   var skipTunnelFix = otherFeatureType === 'waterway' && selectedFeatureType !== 'waterway';
55667
55668                   if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
55669                     fixes.push(makeAddBridgeOrTunnelFix('add_a_tunnel', 'temaki-tunnel', 'tunnel'));
55670                   }
55671                 } // repositioning the features is always an option
55672
55673
55674                 fixes.push(new validationIssueFix({
55675                   icon: 'iD-operation-move',
55676                   title: _t.html('issues.fix.reposition_features.title')
55677                 }));
55678                 return fixes;
55679               }
55680             });
55681
55682             function showReference(selection) {
55683               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.crossing_ways.' + crossingTypeID + '.reference'));
55684             }
55685           }
55686
55687           function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel) {
55688             return new validationIssueFix({
55689               icon: iconName,
55690               title: _t.html('issues.fix.' + fixTitleID + '.title'),
55691               onClick: function onClick(context) {
55692                 var mode = context.mode();
55693                 if (!mode || mode.id !== 'select') return;
55694                 var selectedIDs = mode.selectedIDs();
55695                 if (selectedIDs.length !== 1) return;
55696                 var selectedWayID = selectedIDs[0];
55697                 if (!context.hasEntity(selectedWayID)) return;
55698                 var resultWayIDs = [selectedWayID];
55699                 var edge, crossedEdge, crossedWayID;
55700
55701                 if (this.issue.entityIds[0] === selectedWayID) {
55702                   edge = this.issue.data.edges[0];
55703                   crossedEdge = this.issue.data.edges[1];
55704                   crossedWayID = this.issue.entityIds[1];
55705                 } else {
55706                   edge = this.issue.data.edges[1];
55707                   crossedEdge = this.issue.data.edges[0];
55708                   crossedWayID = this.issue.entityIds[0];
55709                 }
55710
55711                 var crossingLoc = this.issue.loc;
55712                 var projection = context.projection;
55713
55714                 var action = function actionAddStructure(graph) {
55715                   var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
55716                   var crossedWay = graph.hasEntity(crossedWayID); // use the explicit width of the crossed feature as the structure length, if available
55717
55718                   var structLengthMeters = crossedWay && crossedWay.tags.width && parseFloat(crossedWay.tags.width);
55719
55720                   if (!structLengthMeters) {
55721                     // if no explicit width is set, approximate the width based on the tags
55722                     structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
55723                   }
55724
55725                   if (structLengthMeters) {
55726                     if (getFeatureType(crossedWay, graph) === 'railway') {
55727                       // bridges over railways are generally much longer than the rail bed itself, compensate
55728                       structLengthMeters *= 2;
55729                     }
55730                   } else {
55731                     // should ideally never land here since all rail/water/road tags should have an implied width
55732                     structLengthMeters = 8;
55733                   }
55734
55735                   var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection) + Math.PI;
55736                   var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection) + Math.PI;
55737                   var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
55738                   if (crossingAngle > Math.PI) crossingAngle -= Math.PI; // lengthen the structure to account for the angle of the crossing
55739
55740                   structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2; // add padding since the structure must extend past the edges of the crossed feature
55741
55742                   structLengthMeters += 4; // clamp the length to a reasonable range
55743
55744                   structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
55745
55746                   function geomToProj(geoPoint) {
55747                     return [geoLonToMeters(geoPoint[0], geoPoint[1]), geoLatToMeters(geoPoint[1])];
55748                   }
55749
55750                   function projToGeom(projPoint) {
55751                     var lat = geoMetersToLat(projPoint[1]);
55752                     return [geoMetersToLon(projPoint[0], lat), lat];
55753                   }
55754
55755                   var projEdgeNode1 = geomToProj(edgeNodes[0].loc);
55756                   var projEdgeNode2 = geomToProj(edgeNodes[1].loc);
55757                   var projectedAngle = geoVecAngle(projEdgeNode1, projEdgeNode2);
55758                   var projectedCrossingLoc = geomToProj(crossingLoc);
55759                   var linearToSphericalMetersRatio = geoVecLength(projEdgeNode1, projEdgeNode2) / geoSphericalDistance(edgeNodes[0].loc, edgeNodes[1].loc);
55760
55761                   function locSphericalDistanceFromCrossingLoc(angle, distanceMeters) {
55762                     var lengthSphericalMeters = distanceMeters * linearToSphericalMetersRatio;
55763                     return projToGeom([projectedCrossingLoc[0] + Math.cos(angle) * lengthSphericalMeters, projectedCrossingLoc[1] + Math.sin(angle) * lengthSphericalMeters]);
55764                   }
55765
55766                   var endpointLocGetter1 = function endpointLocGetter1(lengthMeters) {
55767                     return locSphericalDistanceFromCrossingLoc(projectedAngle, lengthMeters);
55768                   };
55769
55770                   var endpointLocGetter2 = function endpointLocGetter2(lengthMeters) {
55771                     return locSphericalDistanceFromCrossingLoc(projectedAngle + Math.PI, lengthMeters);
55772                   }; // avoid creating very short edges from splitting too close to another node
55773
55774
55775                   var minEdgeLengthMeters = 0.55; // decide where to bound the structure along the way, splitting as necessary
55776
55777                   function determineEndpoint(edge, endNode, locGetter) {
55778                     var newNode;
55779                     var idealLengthMeters = structLengthMeters / 2; // distance between the crossing location and the end of the edge,
55780                     // the maximum length of this side of the structure
55781
55782                     var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
55783
55784                     if (crossingToEdgeEndDistance - idealLengthMeters > minEdgeLengthMeters) {
55785                       // the edge is long enough to insert a new node
55786                       // the loc that would result in the full expected length
55787                       var idealNodeLoc = locGetter(idealLengthMeters);
55788                       newNode = osmNode();
55789                       graph = actionAddMidpoint({
55790                         loc: idealNodeLoc,
55791                         edge: edge
55792                       }, newNode)(graph);
55793                     } else {
55794                       var edgeCount = 0;
55795                       endNode.parentIntersectionWays(graph).forEach(function (way) {
55796                         way.nodes.forEach(function (nodeID) {
55797                           if (nodeID === endNode.id) {
55798                             if (endNode.id === way.first() && endNode.id !== way.last() || endNode.id === way.last() && endNode.id !== way.first()) {
55799                               edgeCount += 1;
55800                             } else {
55801                               edgeCount += 2;
55802                             }
55803                           }
55804                         });
55805                       });
55806
55807                       if (edgeCount >= 3) {
55808                         // the end node is a junction, try to leave a segment
55809                         // between it and the structure - #7202
55810                         var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
55811
55812                         if (insetLength > minEdgeLengthMeters) {
55813                           var insetNodeLoc = locGetter(insetLength);
55814                           newNode = osmNode();
55815                           graph = actionAddMidpoint({
55816                             loc: insetNodeLoc,
55817                             edge: edge
55818                           }, newNode)(graph);
55819                         }
55820                       }
55821                     } // if the edge is too short to subdivide as desired, then
55822                     // just bound the structure at the existing end node
55823
55824
55825                     if (!newNode) newNode = endNode;
55826                     var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs); // only split selected or created ways
55827                     // do the split
55828
55829                     graph = splitAction(graph);
55830
55831                     if (splitAction.getCreatedWayIDs().length) {
55832                       resultWayIDs.push(splitAction.getCreatedWayIDs()[0]);
55833                     }
55834
55835                     return newNode;
55836                   }
55837
55838                   var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
55839                   var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
55840                   var structureWay = resultWayIDs.map(function (id) {
55841                     return graph.entity(id);
55842                   }).find(function (way) {
55843                     return way.nodes.indexOf(structEndNode1.id) !== -1 && way.nodes.indexOf(structEndNode2.id) !== -1;
55844                   });
55845                   var tags = Object.assign({}, structureWay.tags); // copy tags
55846
55847                   if (bridgeOrTunnel === 'bridge') {
55848                     tags.bridge = 'yes';
55849                     tags.layer = '1';
55850                   } else {
55851                     var tunnelValue = 'yes';
55852
55853                     if (getFeatureType(structureWay, graph) === 'waterway') {
55854                       // use `tunnel=culvert` for waterways by default
55855                       tunnelValue = 'culvert';
55856                     }
55857
55858                     tags.tunnel = tunnelValue;
55859                     tags.layer = '-1';
55860                   } // apply the structure tags to the way
55861
55862
55863                   graph = actionChangeTags(structureWay.id, tags)(graph);
55864                   return graph;
55865                 };
55866
55867                 context.perform(action, _t('issues.fix.' + fixTitleID + '.annotation'));
55868                 context.enter(modeSelect(context, resultWayIDs));
55869               }
55870             });
55871           }
55872
55873           function makeConnectWaysFix(connectionTags) {
55874             var fixTitleID = 'connect_features';
55875
55876             if (connectionTags.ford) {
55877               fixTitleID = 'connect_using_ford';
55878             }
55879
55880             return new validationIssueFix({
55881               icon: 'iD-icon-crossing',
55882               title: _t.html('issues.fix.' + fixTitleID + '.title'),
55883               onClick: function onClick(context) {
55884                 var loc = this.issue.loc;
55885                 var connectionTags = this.issue.data.connectionTags;
55886                 var edges = this.issue.data.edges;
55887                 context.perform(function actionConnectCrossingWays(graph) {
55888                   // create the new node for the points
55889                   var node = osmNode({
55890                     loc: loc,
55891                     tags: connectionTags
55892                   });
55893                   graph = graph.replace(node);
55894                   var nodesToMerge = [node.id];
55895                   var mergeThresholdInMeters = 0.75;
55896                   edges.forEach(function (edge) {
55897                     var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
55898                     var nearby = geoSphericalClosestNode(edgeNodes, loc); // if there is already a suitable node nearby, use that
55899
55900                     if (!nearby.node.hasInterestingTags() && nearby.distance < mergeThresholdInMeters) {
55901                       nodesToMerge.push(nearby.node.id); // else add the new node to the way
55902                     } else {
55903                       graph = actionAddMidpoint({
55904                         loc: loc,
55905                         edge: edge
55906                       }, node)(graph);
55907                     }
55908                   });
55909
55910                   if (nodesToMerge.length > 1) {
55911                     // if we're using nearby nodes, merge them with the new node
55912                     graph = actionMergeNodes(nodesToMerge, loc)(graph);
55913                   }
55914
55915                   return graph;
55916                 }, _t('issues.fix.connect_crossing_features.annotation'));
55917               }
55918             });
55919           }
55920
55921           function makeChangeLayerFix(higherOrLower) {
55922             return new validationIssueFix({
55923               icon: 'iD-icon-' + (higherOrLower === 'higher' ? 'up' : 'down'),
55924               title: _t.html('issues.fix.tag_this_as_' + higherOrLower + '.title'),
55925               onClick: function onClick(context) {
55926                 var mode = context.mode();
55927                 if (!mode || mode.id !== 'select') return;
55928                 var selectedIDs = mode.selectedIDs();
55929                 if (selectedIDs.length !== 1) return;
55930                 var selectedID = selectedIDs[0];
55931                 if (!this.issue.entityIds.some(function (entityId) {
55932                   return entityId === selectedID;
55933                 })) return;
55934                 var entity = context.hasEntity(selectedID);
55935                 if (!entity) return;
55936                 var tags = Object.assign({}, entity.tags); // shallow copy
55937
55938                 var layer = tags.layer && Number(tags.layer);
55939
55940                 if (layer && !isNaN(layer)) {
55941                   if (higherOrLower === 'higher') {
55942                     layer += 1;
55943                   } else {
55944                     layer -= 1;
55945                   }
55946                 } else {
55947                   if (higherOrLower === 'higher') {
55948                     layer = 1;
55949                   } else {
55950                     layer = -1;
55951                   }
55952                 }
55953
55954                 tags.layer = layer.toString();
55955                 context.perform(actionChangeTags(entity.id, tags), _t('operations.change_tags.annotation'));
55956               }
55957             });
55958           }
55959
55960           validation.type = type;
55961           return validation;
55962         }
55963
55964         function behaviorDrawWay(context, wayID, mode, startGraph) {
55965           var dispatch = dispatch$8('rejectedSelfIntersection');
55966           var behavior = behaviorDraw(context); // Must be set by `drawWay.nodeIndex` before each install of this behavior.
55967
55968           var _nodeIndex;
55969
55970           var _origWay;
55971
55972           var _wayGeometry;
55973
55974           var _headNodeID;
55975
55976           var _annotation;
55977
55978           var _pointerHasMoved = false; // The osmNode to be placed.
55979           // This is temporary and just follows the mouse cursor until an "add" event occurs.
55980
55981           var _drawNode;
55982
55983           var _didResolveTempEdit = false;
55984
55985           function createDrawNode(loc) {
55986             // don't make the draw node until we actually need it
55987             _drawNode = osmNode({
55988               loc: loc
55989             });
55990             context.pauseChangeDispatch();
55991             context.replace(function actionAddDrawNode(graph) {
55992               // add the draw node to the graph and insert it into the way
55993               var way = graph.entity(wayID);
55994               return graph.replace(_drawNode).replace(way.addNode(_drawNode.id, _nodeIndex));
55995             }, _annotation);
55996             context.resumeChangeDispatch();
55997             setActiveElements();
55998           }
55999
56000           function removeDrawNode() {
56001             context.pauseChangeDispatch();
56002             context.replace(function actionDeleteDrawNode(graph) {
56003               var way = graph.entity(wayID);
56004               return graph.replace(way.removeNode(_drawNode.id)).remove(_drawNode);
56005             }, _annotation);
56006             _drawNode = undefined;
56007             context.resumeChangeDispatch();
56008           }
56009
56010           function keydown(d3_event) {
56011             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56012               if (context.surface().classed('nope')) {
56013                 context.surface().classed('nope-suppressed', true);
56014               }
56015
56016               context.surface().classed('nope', false).classed('nope-disabled', true);
56017             }
56018           }
56019
56020           function keyup(d3_event) {
56021             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56022               if (context.surface().classed('nope-suppressed')) {
56023                 context.surface().classed('nope', true);
56024               }
56025
56026               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
56027             }
56028           }
56029
56030           function allowsVertex(d) {
56031             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
56032           } // related code
56033           // - `mode/drag_node.js`     `doMove()`
56034           // - `behavior/draw.js`      `click()`
56035           // - `behavior/draw_way.js`  `move()`
56036
56037
56038           function move(d3_event, datum) {
56039             var loc = context.map().mouseCoordinates();
56040             if (!_drawNode) createDrawNode(loc);
56041             context.surface().classed('nope-disabled', d3_event.altKey);
56042             var targetLoc = datum && datum.properties && datum.properties.entity && allowsVertex(datum.properties.entity) && datum.properties.entity.loc;
56043             var targetNodes = datum && datum.properties && datum.properties.nodes;
56044
56045             if (targetLoc) {
56046               // snap to node/vertex - a point target with `.loc`
56047               loc = targetLoc;
56048             } else if (targetNodes) {
56049               // snap to way - a line target with `.nodes`
56050               var choice = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, _drawNode.id);
56051
56052               if (choice) {
56053                 loc = choice.loc;
56054               }
56055             }
56056
56057             context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
56058             _drawNode = context.entity(_drawNode.id);
56059             checkGeometry(true
56060             /* includeDrawNode */
56061             );
56062           } // Check whether this edit causes the geometry to break.
56063           // If so, class the surface with a nope cursor.
56064           // `includeDrawNode` - Only check the relevant line segments if finishing drawing
56065
56066
56067           function checkGeometry(includeDrawNode) {
56068             var nopeDisabled = context.surface().classed('nope-disabled');
56069             var isInvalid = isInvalidGeometry(includeDrawNode);
56070
56071             if (nopeDisabled) {
56072               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
56073             } else {
56074               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
56075             }
56076           }
56077
56078           function isInvalidGeometry(includeDrawNode) {
56079             var testNode = _drawNode; // we only need to test the single way we're drawing
56080
56081             var parentWay = context.graph().entity(wayID);
56082             var nodes = context.graph().childNodes(parentWay).slice(); // shallow copy
56083
56084             if (includeDrawNode) {
56085               if (parentWay.isClosed()) {
56086                 // don't test the last segment for closed ways - #4655
56087                 // (still test the first segment)
56088                 nodes.pop();
56089               }
56090             } else {
56091               // discount the draw node
56092               if (parentWay.isClosed()) {
56093                 if (nodes.length < 3) return false;
56094                 if (_drawNode) nodes.splice(-2, 1);
56095                 testNode = nodes[nodes.length - 2];
56096               } else {
56097                 // there's nothing we need to test if we ignore the draw node on open ways
56098                 return false;
56099               }
56100             }
56101
56102             return testNode && geoHasSelfIntersections(nodes, testNode.id);
56103           }
56104
56105           function undone() {
56106             // undoing removed the temp edit
56107             _didResolveTempEdit = true;
56108             context.pauseChangeDispatch();
56109             var nextMode;
56110
56111             if (context.graph() === startGraph) {
56112               // We've undone back to the initial state before we started drawing.
56113               // Just exit the draw mode without undoing whatever we did before
56114               // we entered the draw mode.
56115               nextMode = modeSelect(context, [wayID]);
56116             } else {
56117               // The `undo` only removed the temporary edit, so here we have to
56118               // manually undo to actually remove the last node we added. We can't
56119               // use the `undo` function since the initial "add" graph doesn't have
56120               // an annotation and so cannot be undone to.
56121               context.pop(1); // continue drawing
56122
56123               nextMode = mode;
56124             } // clear the redo stack by adding and removing a blank edit
56125
56126
56127             context.perform(actionNoop());
56128             context.pop(1);
56129             context.resumeChangeDispatch();
56130             context.enter(nextMode);
56131           }
56132
56133           function setActiveElements() {
56134             if (!_drawNode) return;
56135             context.surface().selectAll('.' + _drawNode.id).classed('active', true);
56136           }
56137
56138           function resetToStartGraph() {
56139             while (context.graph() !== startGraph) {
56140               context.pop();
56141             }
56142           }
56143
56144           var drawWay = function drawWay(surface) {
56145             _drawNode = undefined;
56146             _didResolveTempEdit = false;
56147             _origWay = context.entity(wayID);
56148
56149             if (typeof _nodeIndex === 'number') {
56150               _headNodeID = _origWay.nodes[_nodeIndex];
56151             } else if (_origWay.isClosed()) {
56152               _headNodeID = _origWay.nodes[_origWay.nodes.length - 2];
56153             } else {
56154               _headNodeID = _origWay.nodes[_origWay.nodes.length - 1];
56155             }
56156
56157             _wayGeometry = _origWay.geometry(context.graph());
56158             _annotation = _t((_origWay.nodes.length === (_origWay.isClosed() ? 2 : 1) ? 'operations.start.annotation.' : 'operations.continue.annotation.') + _wayGeometry);
56159             _pointerHasMoved = false; // Push an annotated state for undo to return back to.
56160             // We must make sure to replace or remove it later.
56161
56162             context.pauseChangeDispatch();
56163             context.perform(actionNoop(), _annotation);
56164             context.resumeChangeDispatch();
56165             behavior.hover().initialNodeID(_headNodeID);
56166             behavior.on('move', function () {
56167               _pointerHasMoved = true;
56168               move.apply(this, arguments);
56169             }).on('down', function () {
56170               move.apply(this, arguments);
56171             }).on('downcancel', function () {
56172               if (_drawNode) removeDrawNode();
56173             }).on('click', drawWay.add).on('clickWay', drawWay.addWay).on('clickNode', drawWay.addNode).on('undo', context.undo).on('cancel', drawWay.cancel).on('finish', drawWay.finish);
56174             select(window).on('keydown.drawWay', keydown).on('keyup.drawWay', keyup);
56175             context.map().dblclickZoomEnable(false).on('drawn.draw', setActiveElements);
56176             setActiveElements();
56177             surface.call(behavior);
56178             context.history().on('undone.draw', undone);
56179           };
56180
56181           drawWay.off = function (surface) {
56182             if (!_didResolveTempEdit) {
56183               // Drawing was interrupted unexpectedly.
56184               // This can happen if the user changes modes,
56185               // clicks geolocate button, a hashchange event occurs, etc.
56186               context.pauseChangeDispatch();
56187               resetToStartGraph();
56188               context.resumeChangeDispatch();
56189             }
56190
56191             _drawNode = undefined;
56192             _nodeIndex = undefined;
56193             context.map().on('drawn.draw', null);
56194             surface.call(behavior.off).selectAll('.active').classed('active', false);
56195             surface.classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false);
56196             select(window).on('keydown.drawWay', null).on('keyup.drawWay', null);
56197             context.history().on('undone.draw', null);
56198           };
56199
56200           function attemptAdd(d, loc, doAdd) {
56201             if (_drawNode) {
56202               // move the node to the final loc in case move wasn't called
56203               // consistently (e.g. on touch devices)
56204               context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
56205               _drawNode = context.entity(_drawNode.id);
56206             } else {
56207               createDrawNode(loc);
56208             }
56209
56210             checkGeometry(true
56211             /* includeDrawNode */
56212             );
56213
56214             if (d && d.properties && d.properties.nope || context.surface().classed('nope')) {
56215               if (!_pointerHasMoved) {
56216                 // prevent the temporary draw node from appearing on touch devices
56217                 removeDrawNode();
56218               }
56219
56220               dispatch.call('rejectedSelfIntersection', this);
56221               return; // can't click here
56222             }
56223
56224             context.pauseChangeDispatch();
56225             doAdd(); // we just replaced the temporary edit with the real one
56226
56227             _didResolveTempEdit = true;
56228             context.resumeChangeDispatch();
56229             context.enter(mode);
56230           } // Accept the current position of the drawing node
56231
56232
56233           drawWay.add = function (loc, d) {
56234             attemptAdd(d, loc, function () {// don't need to do anything extra
56235             });
56236           }; // Connect the way to an existing way
56237
56238
56239           drawWay.addWay = function (loc, edge, d) {
56240             attemptAdd(d, loc, function () {
56241               context.replace(actionAddMidpoint({
56242                 loc: loc,
56243                 edge: edge
56244               }, _drawNode), _annotation);
56245             });
56246           }; // Connect the way to an existing node
56247
56248
56249           drawWay.addNode = function (node, d) {
56250             // finish drawing if the mapper targets the prior node
56251             if (node.id === _headNodeID || // or the first node when drawing an area
56252             _origWay.isClosed() && node.id === _origWay.first()) {
56253               drawWay.finish();
56254               return;
56255             }
56256
56257             attemptAdd(d, node.loc, function () {
56258               context.replace(function actionReplaceDrawNode(graph) {
56259                 // remove the temporary draw node and insert the existing node
56260                 // at the same index
56261                 graph = graph.replace(graph.entity(wayID).removeNode(_drawNode.id)).remove(_drawNode);
56262                 return graph.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
56263               }, _annotation);
56264             });
56265           }; // Finish the draw operation, removing the temporary edit.
56266           // If the way has enough nodes to be valid, it's selected.
56267           // Otherwise, delete everything and return to browse mode.
56268
56269
56270           drawWay.finish = function () {
56271             checkGeometry(false
56272             /* includeDrawNode */
56273             );
56274
56275             if (context.surface().classed('nope')) {
56276               dispatch.call('rejectedSelfIntersection', this);
56277               return; // can't click here
56278             }
56279
56280             context.pauseChangeDispatch(); // remove the temporary edit
56281
56282             context.pop(1);
56283             _didResolveTempEdit = true;
56284             context.resumeChangeDispatch();
56285             var way = context.hasEntity(wayID);
56286
56287             if (!way || way.isDegenerate()) {
56288               drawWay.cancel();
56289               return;
56290             }
56291
56292             window.setTimeout(function () {
56293               context.map().dblclickZoomEnable(true);
56294             }, 1000);
56295             var isNewFeature = !mode.isContinuing;
56296             context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature));
56297           }; // Cancel the draw operation, delete everything, and return to browse mode.
56298
56299
56300           drawWay.cancel = function () {
56301             context.pauseChangeDispatch();
56302             resetToStartGraph();
56303             context.resumeChangeDispatch();
56304             window.setTimeout(function () {
56305               context.map().dblclickZoomEnable(true);
56306             }, 1000);
56307             context.surface().classed('nope', false).classed('nope-disabled', false).classed('nope-suppressed', false);
56308             context.enter(modeBrowse(context));
56309           };
56310
56311           drawWay.nodeIndex = function (val) {
56312             if (!arguments.length) return _nodeIndex;
56313             _nodeIndex = val;
56314             return drawWay;
56315           };
56316
56317           drawWay.activeID = function () {
56318             if (!arguments.length) return _drawNode && _drawNode.id; // no assign
56319
56320             return drawWay;
56321           };
56322
56323           return utilRebind(drawWay, dispatch, 'on');
56324         }
56325
56326         function modeDrawLine(context, wayID, startGraph, button, affix, continuing) {
56327           var mode = {
56328             button: button,
56329             id: 'draw-line'
56330           };
56331           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawLine', function () {
56332             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.lines'))();
56333           });
56334           mode.wayID = wayID;
56335           mode.isContinuing = continuing;
56336
56337           mode.enter = function () {
56338             behavior.nodeIndex(affix === 'prefix' ? 0 : undefined);
56339             context.install(behavior);
56340           };
56341
56342           mode.exit = function () {
56343             context.uninstall(behavior);
56344           };
56345
56346           mode.selectedIDs = function () {
56347             return [wayID];
56348           };
56349
56350           mode.activeID = function () {
56351             return behavior && behavior.activeID() || [];
56352           };
56353
56354           return mode;
56355         }
56356
56357         function validationDisconnectedWay() {
56358           var type = 'disconnected_way';
56359
56360           function isTaggedAsHighway(entity) {
56361             return osmRoutableHighwayTagValues[entity.tags.highway];
56362           }
56363
56364           var validation = function checkDisconnectedWay(entity, graph) {
56365             var routingIslandWays = routingIslandForEntity(entity);
56366             if (!routingIslandWays) return [];
56367             return [new validationIssue({
56368               type: type,
56369               subtype: 'highway',
56370               severity: 'warning',
56371               message: function message(context) {
56372                 var entity = this.entityIds.length && context.hasEntity(this.entityIds[0]);
56373                 var label = entity && utilDisplayLabel(entity, context.graph());
56374                 return _t.html('issues.disconnected_way.routable.message', {
56375                   count: this.entityIds.length,
56376                   highway: label
56377                 });
56378               },
56379               reference: showReference,
56380               entityIds: Array.from(routingIslandWays).map(function (way) {
56381                 return way.id;
56382               }),
56383               dynamicFixes: makeFixes
56384             })];
56385
56386             function makeFixes(context) {
56387               var fixes = [];
56388               var singleEntity = this.entityIds.length === 1 && context.hasEntity(this.entityIds[0]);
56389
56390               if (singleEntity) {
56391                 if (singleEntity.type === 'way' && !singleEntity.isClosed()) {
56392                   var textDirection = _mainLocalizer.textDirection();
56393                   var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), 'start');
56394                   if (startFix) fixes.push(startFix);
56395                   var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), 'end');
56396                   if (endFix) fixes.push(endFix);
56397                 }
56398
56399                 if (!fixes.length) {
56400                   fixes.push(new validationIssueFix({
56401                     title: _t.html('issues.fix.connect_feature.title')
56402                   }));
56403                 }
56404
56405                 fixes.push(new validationIssueFix({
56406                   icon: 'iD-operation-delete',
56407                   title: _t.html('issues.fix.delete_feature.title'),
56408                   entityIds: [singleEntity.id],
56409                   onClick: function onClick(context) {
56410                     var id = this.issue.entityIds[0];
56411                     var operation = operationDelete(context, [id]);
56412
56413                     if (!operation.disabled()) {
56414                       operation();
56415                     }
56416                   }
56417                 }));
56418               } else {
56419                 fixes.push(new validationIssueFix({
56420                   title: _t.html('issues.fix.connect_features.title')
56421                 }));
56422               }
56423
56424               return fixes;
56425             }
56426
56427             function showReference(selection) {
56428               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.disconnected_way.routable.reference'));
56429             }
56430
56431             function routingIslandForEntity(entity) {
56432               var routingIsland = new Set(); // the interconnected routable features
56433
56434               var waysToCheck = []; // the queue of remaining routable ways to traverse
56435
56436               function queueParentWays(node) {
56437                 graph.parentWays(node).forEach(function (parentWay) {
56438                   if (!routingIsland.has(parentWay) && // only check each feature once
56439                   isRoutableWay(parentWay, false)) {
56440                     // only check routable features
56441                     routingIsland.add(parentWay);
56442                     waysToCheck.push(parentWay);
56443                   }
56444                 });
56445               }
56446
56447               if (entity.type === 'way' && isRoutableWay(entity, true)) {
56448                 routingIsland.add(entity);
56449                 waysToCheck.push(entity);
56450               } else if (entity.type === 'node' && isRoutableNode(entity)) {
56451                 routingIsland.add(entity);
56452                 queueParentWays(entity);
56453               } else {
56454                 // this feature isn't routable, cannot be a routing island
56455                 return null;
56456               }
56457
56458               while (waysToCheck.length) {
56459                 var wayToCheck = waysToCheck.pop();
56460                 var childNodes = graph.childNodes(wayToCheck);
56461
56462                 for (var i in childNodes) {
56463                   var vertex = childNodes[i];
56464
56465                   if (isConnectedVertex(vertex)) {
56466                     // found a link to the wider network, not a routing island
56467                     return null;
56468                   }
56469
56470                   if (isRoutableNode(vertex)) {
56471                     routingIsland.add(vertex);
56472                   }
56473
56474                   queueParentWays(vertex);
56475                 }
56476               } // no network link found, this is a routing island, return its members
56477
56478
56479               return routingIsland;
56480             }
56481
56482             function isConnectedVertex(vertex) {
56483               // assume ways overlapping unloaded tiles are connected to the wider road network  - #5938
56484               var osm = services.osm;
56485               if (osm && !osm.isDataLoaded(vertex.loc)) return true; // entrances are considered connected
56486
56487               if (vertex.tags.entrance && vertex.tags.entrance !== 'no') return true;
56488               if (vertex.tags.amenity === 'parking_entrance') return true;
56489               return false;
56490             }
56491
56492             function isRoutableNode(node) {
56493               // treat elevators as distinct features in the highway network
56494               if (node.tags.highway === 'elevator') return true;
56495               return false;
56496             }
56497
56498             function isRoutableWay(way, ignoreInnerWays) {
56499               if (isTaggedAsHighway(way) || way.tags.route === 'ferry') return true;
56500               return graph.parentRelations(way).some(function (parentRelation) {
56501                 if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true;
56502                 if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== 'inner')) return true;
56503                 return false;
56504               });
56505             }
56506
56507             function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
56508               var vertex = graph.hasEntity(vertexID);
56509               if (!vertex || vertex.tags.noexit === 'yes') return null;
56510               var useLeftContinue = whichEnd === 'start' && textDirection === 'ltr' || whichEnd === 'end' && textDirection === 'rtl';
56511               return new validationIssueFix({
56512                 icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
56513                 title: _t.html('issues.fix.continue_from_' + whichEnd + '.title'),
56514                 entityIds: [vertexID],
56515                 onClick: function onClick(context) {
56516                   var wayId = this.issue.entityIds[0];
56517                   var way = context.hasEntity(wayId);
56518                   var vertexId = this.entityIds[0];
56519                   var vertex = context.hasEntity(vertexId);
56520                   if (!way || !vertex) return; // make sure the vertex is actually visible and editable
56521
56522                   var map = context.map();
56523
56524                   if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
56525                     map.zoomToEase(vertex);
56526                   }
56527
56528                   context.enter(modeDrawLine(context, wayId, context.graph(), 'line', way.affix(vertexId), true));
56529                 }
56530               });
56531             }
56532           };
56533
56534           validation.type = type;
56535           return validation;
56536         }
56537
56538         function validationFormatting() {
56539           var type = 'invalid_format';
56540
56541           var validation = function validation(entity) {
56542             var issues = [];
56543
56544             function isValidEmail(email) {
56545               // Emails in OSM are going to be official so they should be pretty simple
56546               // Using negated lists to better support all possible unicode characters (#6494)
56547               var valid_email = /^[^\(\)\\,":;<>@\[\]]+@[^\(\)\\,":;<>@\[\]\.]+(?:\.[a-z0-9-]+)*$/i; // An empty value is also acceptable
56548
56549               return !email || valid_email.test(email);
56550             }
56551             /*
56552             function isSchemePresent(url) {
56553                 var valid_scheme = /^https?:\/\//i;
56554                 return (!url || valid_scheme.test(url));
56555             }
56556             */
56557
56558
56559             function showReferenceEmail(selection) {
56560               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.invalid_format.email.reference'));
56561             }
56562             /*
56563             function showReferenceWebsite(selection) {
56564                 selection.selectAll('.issue-reference')
56565                     .data([0])
56566                     .enter()
56567                     .append('div')
56568                     .attr('class', 'issue-reference')
56569                     .html(t.html('issues.invalid_format.website.reference'));
56570             }
56571              if (entity.tags.website) {
56572                 // Multiple websites are possible
56573                 // If ever we support ES6, arrow functions make this nicer
56574                 var websites = entity.tags.website
56575                     .split(';')
56576                     .map(function(s) { return s.trim(); })
56577                     .filter(function(x) { return !isSchemePresent(x); });
56578                  if (websites.length) {
56579                     issues.push(new validationIssue({
56580                         type: type,
56581                         subtype: 'website',
56582                         severity: 'warning',
56583                         message: function(context) {
56584                             var entity = context.hasEntity(this.entityIds[0]);
56585                             return entity ? t.html('issues.invalid_format.website.message' + this.data,
56586                                 { feature: utilDisplayLabel(entity, context.graph()), site: websites.join(', ') }) : '';
56587                         },
56588                         reference: showReferenceWebsite,
56589                         entityIds: [entity.id],
56590                         hash: websites.join(),
56591                         data: (websites.length > 1) ? '_multi' : ''
56592                     }));
56593                 }
56594             }
56595             */
56596
56597
56598             if (entity.tags.email) {
56599               // Multiple emails are possible
56600               var emails = entity.tags.email.split(';').map(function (s) {
56601                 return s.trim();
56602               }).filter(function (x) {
56603                 return !isValidEmail(x);
56604               });
56605
56606               if (emails.length) {
56607                 issues.push(new validationIssue({
56608                   type: type,
56609                   subtype: 'email',
56610                   severity: 'warning',
56611                   message: function message(context) {
56612                     var entity = context.hasEntity(this.entityIds[0]);
56613                     return entity ? _t.html('issues.invalid_format.email.message' + this.data, {
56614                       feature: utilDisplayLabel(entity, context.graph()),
56615                       email: emails.join(', ')
56616                     }) : '';
56617                   },
56618                   reference: showReferenceEmail,
56619                   entityIds: [entity.id],
56620                   hash: emails.join(),
56621                   data: emails.length > 1 ? '_multi' : ''
56622                 }));
56623               }
56624             }
56625
56626             return issues;
56627           };
56628
56629           validation.type = type;
56630           return validation;
56631         }
56632
56633         function validationHelpRequest(context) {
56634           var type = 'help_request';
56635
56636           var validation = function checkFixmeTag(entity) {
56637             if (!entity.tags.fixme) return []; // don't flag fixmes on features added by the user
56638
56639             if (entity.version === undefined) return [];
56640
56641             if (entity.v !== undefined) {
56642               var baseEntity = context.history().base().hasEntity(entity.id); // don't flag fixmes added by the user on existing features
56643
56644               if (!baseEntity || !baseEntity.tags.fixme) return [];
56645             }
56646
56647             return [new validationIssue({
56648               type: type,
56649               subtype: 'fixme_tag',
56650               severity: 'warning',
56651               message: function message(context) {
56652                 var entity = context.hasEntity(this.entityIds[0]);
56653                 return entity ? _t.html('issues.fixme_tag.message', {
56654                   feature: utilDisplayLabel(entity, context.graph(), true
56655                   /* verbose */
56656                   )
56657                 }) : '';
56658               },
56659               dynamicFixes: function dynamicFixes() {
56660                 return [new validationIssueFix({
56661                   title: _t.html('issues.fix.address_the_concern.title')
56662                 })];
56663               },
56664               reference: showReference,
56665               entityIds: [entity.id]
56666             })];
56667
56668             function showReference(selection) {
56669               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.fixme_tag.reference'));
56670             }
56671           };
56672
56673           validation.type = type;
56674           return validation;
56675         }
56676
56677         function validationImpossibleOneway() {
56678           var type = 'impossible_oneway';
56679
56680           var validation = function checkImpossibleOneway(entity, graph) {
56681             if (entity.type !== 'way' || entity.geometry(graph) !== 'line') return [];
56682             if (entity.isClosed()) return [];
56683             if (!typeForWay(entity)) return [];
56684             if (!isOneway(entity)) return [];
56685             var firstIssues = issuesForNode(entity, entity.first());
56686             var lastIssues = issuesForNode(entity, entity.last());
56687             return firstIssues.concat(lastIssues);
56688
56689             function typeForWay(way) {
56690               if (way.geometry(graph) !== 'line') return null;
56691               if (osmRoutableHighwayTagValues[way.tags.highway]) return 'highway';
56692               if (osmFlowingWaterwayTagValues[way.tags.waterway]) return 'waterway';
56693               return null;
56694             }
56695
56696             function isOneway(way) {
56697               if (way.tags.oneway === 'yes') return true;
56698               if (way.tags.oneway) return false;
56699
56700               for (var key in way.tags) {
56701                 if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
56702                   return true;
56703                 }
56704               }
56705
56706               return false;
56707             }
56708
56709             function nodeOccursMoreThanOnce(way, nodeID) {
56710               var occurrences = 0;
56711
56712               for (var index in way.nodes) {
56713                 if (way.nodes[index] === nodeID) {
56714                   occurrences += 1;
56715                   if (occurrences > 1) return true;
56716                 }
56717               }
56718
56719               return false;
56720             }
56721
56722             function isConnectedViaOtherTypes(way, node) {
56723               var wayType = typeForWay(way);
56724
56725               if (wayType === 'highway') {
56726                 // entrances are considered connected
56727                 if (node.tags.entrance && node.tags.entrance !== 'no') return true;
56728                 if (node.tags.amenity === 'parking_entrance') return true;
56729               } else if (wayType === 'waterway') {
56730                 if (node.id === way.first()) {
56731                   // multiple waterways may start at the same spring
56732                   if (node.tags.natural === 'spring') return true;
56733                 } else {
56734                   // multiple waterways may end at the same drain
56735                   if (node.tags.manhole === 'drain') return true;
56736                 }
56737               }
56738
56739               return graph.parentWays(node).some(function (parentWay) {
56740                 if (parentWay.id === way.id) return false;
56741
56742                 if (wayType === 'highway') {
56743                   // allow connections to highway areas
56744                   if (parentWay.geometry(graph) === 'area' && osmRoutableHighwayTagValues[parentWay.tags.highway]) return true; // count connections to ferry routes as connected
56745
56746                   if (parentWay.tags.route === 'ferry') return true;
56747                   return graph.parentRelations(parentWay).some(function (parentRelation) {
56748                     if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true; // allow connections to highway multipolygons
56749
56750                     return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
56751                   });
56752                 } else if (wayType === 'waterway') {
56753                   // multiple waterways may start or end at a water body at the same node
56754                   if (parentWay.tags.natural === 'water' || parentWay.tags.natural === 'coastline') return true;
56755                 }
56756
56757                 return false;
56758               });
56759             }
56760
56761             function issuesForNode(way, nodeID) {
56762               var isFirst = nodeID === way.first();
56763               var wayType = typeForWay(way); // ignore if this way is self-connected at this node
56764
56765               if (nodeOccursMoreThanOnce(way, nodeID)) return [];
56766               var osm = services.osm;
56767               if (!osm) return [];
56768               var node = graph.hasEntity(nodeID); // ignore if this node or its tile are unloaded
56769
56770               if (!node || !osm.isDataLoaded(node.loc)) return [];
56771               if (isConnectedViaOtherTypes(way, node)) return [];
56772               var attachedWaysOfSameType = graph.parentWays(node).filter(function (parentWay) {
56773                 if (parentWay.id === way.id) return false;
56774                 return typeForWay(parentWay) === wayType;
56775               }); // assume it's okay for waterways to start or end disconnected for now
56776
56777               if (wayType === 'waterway' && attachedWaysOfSameType.length === 0) return [];
56778               var attachedOneways = attachedWaysOfSameType.filter(function (attachedWay) {
56779                 return isOneway(attachedWay);
56780               }); // ignore if the way is connected to some non-oneway features
56781
56782               if (attachedOneways.length < attachedWaysOfSameType.length) return [];
56783
56784               if (attachedOneways.length) {
56785                 var connectedEndpointsOkay = attachedOneways.some(function (attachedOneway) {
56786                   if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID) return true;
56787                   if (nodeOccursMoreThanOnce(attachedOneway, nodeID)) return true;
56788                   return false;
56789                 });
56790                 if (connectedEndpointsOkay) return [];
56791               }
56792
56793               var placement = isFirst ? 'start' : 'end',
56794                   messageID = wayType + '.',
56795                   referenceID = wayType + '.';
56796
56797               if (wayType === 'waterway') {
56798                 messageID += 'connected.' + placement;
56799                 referenceID += 'connected';
56800               } else {
56801                 messageID += placement;
56802                 referenceID += placement;
56803               }
56804
56805               return [new validationIssue({
56806                 type: type,
56807                 subtype: wayType,
56808                 severity: 'warning',
56809                 message: function message(context) {
56810                   var entity = context.hasEntity(this.entityIds[0]);
56811                   return entity ? _t.html('issues.impossible_oneway.' + messageID + '.message', {
56812                     feature: utilDisplayLabel(entity, context.graph())
56813                   }) : '';
56814                 },
56815                 reference: getReference(referenceID),
56816                 entityIds: [way.id, node.id],
56817                 dynamicFixes: function dynamicFixes() {
56818                   var fixes = [];
56819
56820                   if (attachedOneways.length) {
56821                     fixes.push(new validationIssueFix({
56822                       icon: 'iD-operation-reverse',
56823                       title: _t.html('issues.fix.reverse_feature.title'),
56824                       entityIds: [way.id],
56825                       onClick: function onClick(context) {
56826                         var id = this.issue.entityIds[0];
56827                         context.perform(actionReverse(id), _t('operations.reverse.annotation.line', {
56828                           n: 1
56829                         }));
56830                       }
56831                     }));
56832                   }
56833
56834                   if (node.tags.noexit !== 'yes') {
56835                     var textDirection = _mainLocalizer.textDirection();
56836                     var useLeftContinue = isFirst && textDirection === 'ltr' || !isFirst && textDirection === 'rtl';
56837                     fixes.push(new validationIssueFix({
56838                       icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
56839                       title: _t.html('issues.fix.continue_from_' + (isFirst ? 'start' : 'end') + '.title'),
56840                       onClick: function onClick(context) {
56841                         var entityID = this.issue.entityIds[0];
56842                         var vertexID = this.issue.entityIds[1];
56843                         var way = context.entity(entityID);
56844                         var vertex = context.entity(vertexID);
56845                         continueDrawing(way, vertex, context);
56846                       }
56847                     }));
56848                   }
56849
56850                   return fixes;
56851                 },
56852                 loc: node.loc
56853               })];
56854
56855               function getReference(referenceID) {
56856                 return function showReference(selection) {
56857                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.impossible_oneway.' + referenceID + '.reference'));
56858                 };
56859               }
56860             }
56861           };
56862
56863           function continueDrawing(way, vertex, context) {
56864             // make sure the vertex is actually visible and editable
56865             var map = context.map();
56866
56867             if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
56868               map.zoomToEase(vertex);
56869             }
56870
56871             context.enter(modeDrawLine(context, way.id, context.graph(), 'line', way.affix(vertex.id), true));
56872           }
56873
56874           validation.type = type;
56875           return validation;
56876         }
56877
56878         function validationIncompatibleSource() {
56879           var type = 'incompatible_source';
56880           var invalidSources = [{
56881             id: 'google',
56882             regex: 'google',
56883             exceptRegex: 'books.google|Google Books|drive.google|googledrive|Google Drive'
56884           }];
56885
56886           var validation = function checkIncompatibleSource(entity) {
56887             var entitySources = entity.tags && entity.tags.source && entity.tags.source.split(';');
56888             if (!entitySources) return [];
56889             var issues = [];
56890             invalidSources.forEach(function (invalidSource) {
56891               var hasInvalidSource = entitySources.some(function (source) {
56892                 if (!source.match(new RegExp(invalidSource.regex, 'i'))) return false;
56893                 if (invalidSource.exceptRegex && source.match(new RegExp(invalidSource.exceptRegex, 'i'))) return false;
56894                 return true;
56895               });
56896               if (!hasInvalidSource) return;
56897               issues.push(new validationIssue({
56898                 type: type,
56899                 severity: 'warning',
56900                 message: function message(context) {
56901                   var entity = context.hasEntity(this.entityIds[0]);
56902                   return entity ? _t.html('issues.incompatible_source.' + invalidSource.id + '.feature.message', {
56903                     feature: utilDisplayLabel(entity, context.graph(), true
56904                     /* verbose */
56905                     )
56906                   }) : '';
56907                 },
56908                 reference: getReference(invalidSource.id),
56909                 entityIds: [entity.id],
56910                 dynamicFixes: function dynamicFixes() {
56911                   return [new validationIssueFix({
56912                     title: _t.html('issues.fix.remove_proprietary_data.title')
56913                   })];
56914                 }
56915               }));
56916             });
56917             return issues;
56918
56919             function getReference(id) {
56920               return function showReference(selection) {
56921                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.incompatible_source.' + id + '.reference'));
56922               };
56923             }
56924           };
56925
56926           validation.type = type;
56927           return validation;
56928         }
56929
56930         function validationMaprules() {
56931           var type = 'maprules';
56932
56933           var validation = function checkMaprules(entity, graph) {
56934             if (!services.maprules) return [];
56935             var rules = services.maprules.validationRules();
56936             var issues = [];
56937
56938             for (var i = 0; i < rules.length; i++) {
56939               var rule = rules[i];
56940               rule.findIssues(entity, graph, issues);
56941             }
56942
56943             return issues;
56944           };
56945
56946           validation.type = type;
56947           return validation;
56948         }
56949
56950         function validationMismatchedGeometry() {
56951           var type = 'mismatched_geometry';
56952
56953           function tagSuggestingLineIsArea(entity) {
56954             if (entity.type !== 'way' || entity.isClosed()) return null;
56955             var tagSuggestingArea = entity.tagSuggestingArea();
56956
56957             if (!tagSuggestingArea) {
56958               return null;
56959             }
56960
56961             var asLine = _mainPresetIndex.matchTags(tagSuggestingArea, 'line');
56962             var asArea = _mainPresetIndex.matchTags(tagSuggestingArea, 'area');
56963
56964             if (asLine && asArea && asLine === asArea) {
56965               // these tags also allow lines and making this an area wouldn't matter
56966               return null;
56967             }
56968
56969             return tagSuggestingArea;
56970           }
56971
56972           function makeConnectEndpointsFixOnClick(way, graph) {
56973             // must have at least three nodes to close this automatically
56974             if (way.nodes.length < 3) return null;
56975             var nodes = graph.childNodes(way),
56976                 testNodes;
56977             var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc); // if the distance is very small, attempt to merge the endpoints
56978
56979             if (firstToLastDistanceMeters < 0.75) {
56980               testNodes = nodes.slice(); // shallow copy
56981
56982               testNodes.pop();
56983               testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
56984
56985               if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
56986                 return function (context) {
56987                   var way = context.entity(this.issue.entityIds[0]);
56988                   context.perform(actionMergeNodes([way.nodes[0], way.nodes[way.nodes.length - 1]], nodes[0].loc), _t('issues.fix.connect_endpoints.annotation'));
56989                 };
56990               }
56991             } // if the points were not merged, attempt to close the way
56992
56993
56994             testNodes = nodes.slice(); // shallow copy
56995
56996             testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
56997
56998             if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
56999               return function (context) {
57000                 var wayId = this.issue.entityIds[0];
57001                 var way = context.entity(wayId);
57002                 var nodeId = way.nodes[0];
57003                 var index = way.nodes.length;
57004                 context.perform(actionAddVertex(wayId, nodeId, index), _t('issues.fix.connect_endpoints.annotation'));
57005               };
57006             }
57007           }
57008
57009           function lineTaggedAsAreaIssue(entity) {
57010             var tagSuggestingArea = tagSuggestingLineIsArea(entity);
57011             if (!tagSuggestingArea) return null;
57012             return new validationIssue({
57013               type: type,
57014               subtype: 'area_as_line',
57015               severity: 'warning',
57016               message: function message(context) {
57017                 var entity = context.hasEntity(this.entityIds[0]);
57018                 return entity ? _t.html('issues.tag_suggests_area.message', {
57019                   feature: utilDisplayLabel(entity, 'area', true
57020                   /* verbose */
57021                   ),
57022                   tag: utilTagText({
57023                     tags: tagSuggestingArea
57024                   })
57025                 }) : '';
57026               },
57027               reference: showReference,
57028               entityIds: [entity.id],
57029               hash: JSON.stringify(tagSuggestingArea),
57030               dynamicFixes: function dynamicFixes(context) {
57031                 var fixes = [];
57032                 var entity = context.entity(this.entityIds[0]);
57033                 var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity, context.graph());
57034                 fixes.push(new validationIssueFix({
57035                   title: _t.html('issues.fix.connect_endpoints.title'),
57036                   onClick: connectEndsOnClick
57037                 }));
57038                 fixes.push(new validationIssueFix({
57039                   icon: 'iD-operation-delete',
57040                   title: _t.html('issues.fix.remove_tag.title'),
57041                   onClick: function onClick(context) {
57042                     var entityId = this.issue.entityIds[0];
57043                     var entity = context.entity(entityId);
57044                     var tags = Object.assign({}, entity.tags); // shallow copy
57045
57046                     for (var key in tagSuggestingArea) {
57047                       delete tags[key];
57048                     }
57049
57050                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_tag.annotation'));
57051                   }
57052                 }));
57053                 return fixes;
57054               }
57055             });
57056
57057             function showReference(selection) {
57058               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.tag_suggests_area.reference'));
57059             }
57060           }
57061
57062           function vertexPointIssue(entity, graph) {
57063             // we only care about nodes
57064             if (entity.type !== 'node') return null; // ignore tagless points
57065
57066             if (Object.keys(entity.tags).length === 0) return null; // address lines are special so just ignore them
57067
57068             if (entity.isOnAddressLine(graph)) return null;
57069             var geometry = entity.geometry(graph);
57070             var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
57071
57072             if (geometry === 'point' && !allowedGeometries.point && allowedGeometries.vertex) {
57073               return new validationIssue({
57074                 type: type,
57075                 subtype: 'vertex_as_point',
57076                 severity: 'warning',
57077                 message: function message(context) {
57078                   var entity = context.hasEntity(this.entityIds[0]);
57079                   return entity ? _t.html('issues.vertex_as_point.message', {
57080                     feature: utilDisplayLabel(entity, 'vertex', true
57081                     /* verbose */
57082                     )
57083                   }) : '';
57084                 },
57085                 reference: function showReference(selection) {
57086                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.vertex_as_point.reference'));
57087                 },
57088                 entityIds: [entity.id]
57089               });
57090             } else if (geometry === 'vertex' && !allowedGeometries.vertex && allowedGeometries.point) {
57091               return new validationIssue({
57092                 type: type,
57093                 subtype: 'point_as_vertex',
57094                 severity: 'warning',
57095                 message: function message(context) {
57096                   var entity = context.hasEntity(this.entityIds[0]);
57097                   return entity ? _t.html('issues.point_as_vertex.message', {
57098                     feature: utilDisplayLabel(entity, 'point', true
57099                     /* verbose */
57100                     )
57101                   }) : '';
57102                 },
57103                 reference: function showReference(selection) {
57104                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.point_as_vertex.reference'));
57105                 },
57106                 entityIds: [entity.id],
57107                 dynamicFixes: extractPointDynamicFixes
57108               });
57109             }
57110
57111             return null;
57112           }
57113
57114           function otherMismatchIssue(entity, graph) {
57115             // ignore boring features
57116             if (!entity.hasInterestingTags()) return null;
57117             if (entity.type !== 'node' && entity.type !== 'way') return null; // address lines are special so just ignore them
57118
57119             if (entity.type === 'node' && entity.isOnAddressLine(graph)) return null;
57120             var sourceGeom = entity.geometry(graph);
57121             var targetGeoms = entity.type === 'way' ? ['point', 'vertex'] : ['line', 'area'];
57122             if (sourceGeom === 'area') targetGeoms.unshift('line');
57123             var targetGeom = targetGeoms.find(function (nodeGeom) {
57124               var asSource = _mainPresetIndex.matchTags(entity.tags, sourceGeom);
57125               var asTarget = _mainPresetIndex.matchTags(entity.tags, nodeGeom);
57126               if (!asSource || !asTarget || asSource === asTarget || // sometimes there are two presets with the same tags for different geometries
57127               fastDeepEqual(asSource.tags, asTarget.tags)) return false;
57128               if (asTarget.isFallback()) return false;
57129               var primaryKey = Object.keys(asTarget.tags)[0]; // special case: buildings-as-points are discouraged by iD, but common in OSM, so ignore them
57130
57131               if (primaryKey === 'building') return false;
57132               if (asTarget.tags[primaryKey] === '*') return false;
57133               return asSource.isFallback() || asSource.tags[primaryKey] === '*';
57134             });
57135             if (!targetGeom) return null;
57136             var subtype = targetGeom + '_as_' + sourceGeom;
57137             if (targetGeom === 'vertex') targetGeom = 'point';
57138             if (sourceGeom === 'vertex') sourceGeom = 'point';
57139             var referenceId = targetGeom + '_as_' + sourceGeom;
57140             var dynamicFixes;
57141
57142             if (targetGeom === 'point') {
57143               dynamicFixes = extractPointDynamicFixes;
57144             } else if (sourceGeom === 'area' && targetGeom === 'line') {
57145               dynamicFixes = lineToAreaDynamicFixes;
57146             }
57147
57148             return new validationIssue({
57149               type: type,
57150               subtype: subtype,
57151               severity: 'warning',
57152               message: function message(context) {
57153                 var entity = context.hasEntity(this.entityIds[0]);
57154                 return entity ? _t.html('issues.' + referenceId + '.message', {
57155                   feature: utilDisplayLabel(entity, targetGeom, true
57156                   /* verbose */
57157                   )
57158                 }) : '';
57159               },
57160               reference: function showReference(selection) {
57161                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.mismatched_geometry.reference'));
57162               },
57163               entityIds: [entity.id],
57164               dynamicFixes: dynamicFixes
57165             });
57166           }
57167
57168           function lineToAreaDynamicFixes(context) {
57169             var convertOnClick;
57170             var entityId = this.entityIds[0];
57171             var entity = context.entity(entityId);
57172             var tags = Object.assign({}, entity.tags); // shallow copy
57173
57174             delete tags.area;
57175
57176             if (!osmTagSuggestingArea(tags)) {
57177               // if removing the area tag would make this a line, offer that as a quick fix
57178               convertOnClick = function convertOnClick(context) {
57179                 var entityId = this.issue.entityIds[0];
57180                 var entity = context.entity(entityId);
57181                 var tags = Object.assign({}, entity.tags); // shallow copy
57182
57183                 if (tags.area) {
57184                   delete tags.area;
57185                 }
57186
57187                 context.perform(actionChangeTags(entityId, tags), _t('issues.fix.convert_to_line.annotation'));
57188               };
57189             }
57190
57191             return [new validationIssueFix({
57192               icon: 'iD-icon-line',
57193               title: _t.html('issues.fix.convert_to_line.title'),
57194               onClick: convertOnClick
57195             })];
57196           }
57197
57198           function extractPointDynamicFixes(context) {
57199             var entityId = this.entityIds[0];
57200             var extractOnClick = null;
57201
57202             if (!context.hasHiddenConnections(entityId)) {
57203               extractOnClick = function extractOnClick(context) {
57204                 var entityId = this.issue.entityIds[0];
57205                 var action = actionExtract(entityId, context.projection);
57206                 context.perform(action, _t('operations.extract.annotation', {
57207                   n: 1
57208                 })); // re-enter mode to trigger updates
57209
57210                 context.enter(modeSelect(context, [action.getExtractedNodeID()]));
57211               };
57212             }
57213
57214             return [new validationIssueFix({
57215               icon: 'iD-operation-extract',
57216               title: _t.html('issues.fix.extract_point.title'),
57217               onClick: extractOnClick
57218             })];
57219           }
57220
57221           function unclosedMultipolygonPartIssues(entity, graph) {
57222             if (entity.type !== 'relation' || !entity.isMultipolygon() || entity.isDegenerate() || // cannot determine issues for incompletely-downloaded relations
57223             !entity.isComplete(graph)) return [];
57224             var sequences = osmJoinWays(entity.members, graph);
57225             var issues = [];
57226
57227             for (var i in sequences) {
57228               var sequence = sequences[i];
57229               if (!sequence.nodes) continue;
57230               var firstNode = sequence.nodes[0];
57231               var lastNode = sequence.nodes[sequence.nodes.length - 1]; // part is closed if the first and last nodes are the same
57232
57233               if (firstNode === lastNode) continue;
57234               var issue = new validationIssue({
57235                 type: type,
57236                 subtype: 'unclosed_multipolygon_part',
57237                 severity: 'warning',
57238                 message: function message(context) {
57239                   var entity = context.hasEntity(this.entityIds[0]);
57240                   return entity ? _t.html('issues.unclosed_multipolygon_part.message', {
57241                     feature: utilDisplayLabel(entity, context.graph(), true
57242                     /* verbose */
57243                     )
57244                   }) : '';
57245                 },
57246                 reference: showReference,
57247                 loc: sequence.nodes[0].loc,
57248                 entityIds: [entity.id],
57249                 hash: sequence.map(function (way) {
57250                   return way.id;
57251                 }).join()
57252               });
57253               issues.push(issue);
57254             }
57255
57256             return issues;
57257
57258             function showReference(selection) {
57259               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unclosed_multipolygon_part.reference'));
57260             }
57261           }
57262
57263           var validation = function checkMismatchedGeometry(entity, graph) {
57264             var vertexPoint = vertexPointIssue(entity, graph);
57265             if (vertexPoint) return [vertexPoint];
57266             var lineAsArea = lineTaggedAsAreaIssue(entity);
57267             if (lineAsArea) return [lineAsArea];
57268             var mismatch = otherMismatchIssue(entity, graph);
57269             if (mismatch) return [mismatch];
57270             return unclosedMultipolygonPartIssues(entity, graph);
57271           };
57272
57273           validation.type = type;
57274           return validation;
57275         }
57276
57277         function validationMissingRole() {
57278           var type = 'missing_role';
57279
57280           var validation = function checkMissingRole(entity, graph) {
57281             var issues = [];
57282
57283             if (entity.type === 'way') {
57284               graph.parentRelations(entity).forEach(function (relation) {
57285                 if (!relation.isMultipolygon()) return;
57286                 var member = relation.memberById(entity.id);
57287
57288                 if (member && isMissingRole(member)) {
57289                   issues.push(makeIssue(entity, relation, member));
57290                 }
57291               });
57292             } else if (entity.type === 'relation' && entity.isMultipolygon()) {
57293               entity.indexedMembers().forEach(function (member) {
57294                 var way = graph.hasEntity(member.id);
57295
57296                 if (way && isMissingRole(member)) {
57297                   issues.push(makeIssue(way, entity, member));
57298                 }
57299               });
57300             }
57301
57302             return issues;
57303           };
57304
57305           function isMissingRole(member) {
57306             return !member.role || !member.role.trim().length;
57307           }
57308
57309           function makeIssue(way, relation, member) {
57310             return new validationIssue({
57311               type: type,
57312               severity: 'warning',
57313               message: function message(context) {
57314                 var member = context.hasEntity(this.entityIds[1]),
57315                     relation = context.hasEntity(this.entityIds[0]);
57316                 return member && relation ? _t.html('issues.missing_role.message', {
57317                   member: utilDisplayLabel(member, context.graph()),
57318                   relation: utilDisplayLabel(relation, context.graph())
57319                 }) : '';
57320               },
57321               reference: showReference,
57322               entityIds: [relation.id, way.id],
57323               data: {
57324                 member: member
57325               },
57326               hash: member.index.toString(),
57327               dynamicFixes: function dynamicFixes() {
57328                 return [makeAddRoleFix('inner'), makeAddRoleFix('outer'), new validationIssueFix({
57329                   icon: 'iD-operation-delete',
57330                   title: _t.html('issues.fix.remove_from_relation.title'),
57331                   onClick: function onClick(context) {
57332                     context.perform(actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index), _t('operations.delete_member.annotation', {
57333                       n: 1
57334                     }));
57335                   }
57336                 })];
57337               }
57338             });
57339
57340             function showReference(selection) {
57341               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.missing_role.multipolygon.reference'));
57342             }
57343           }
57344
57345           function makeAddRoleFix(role) {
57346             return new validationIssueFix({
57347               title: _t.html('issues.fix.set_as_' + role + '.title'),
57348               onClick: function onClick(context) {
57349                 var oldMember = this.issue.data.member;
57350                 var member = {
57351                   id: this.issue.entityIds[1],
57352                   type: oldMember.type,
57353                   role: role
57354                 };
57355                 context.perform(actionChangeMember(this.issue.entityIds[0], member, oldMember.index), _t('operations.change_role.annotation', {
57356                   n: 1
57357                 }));
57358               }
57359             });
57360           }
57361
57362           validation.type = type;
57363           return validation;
57364         }
57365
57366         function validationMissingTag(context) {
57367           var type = 'missing_tag';
57368
57369           function hasDescriptiveTags(entity, graph) {
57370             var onlyAttributeKeys = ['description', 'name', 'note', 'start_date'];
57371             var entityDescriptiveKeys = Object.keys(entity.tags).filter(function (k) {
57372               if (k === 'area' || !osmIsInterestingTag(k)) return false;
57373               return !onlyAttributeKeys.some(function (attributeKey) {
57374                 return k === attributeKey || k.indexOf(attributeKey + ':') === 0;
57375               });
57376             });
57377
57378             if (entity.type === 'relation' && entityDescriptiveKeys.length === 1 && entity.tags.type === 'multipolygon') {
57379               // this relation's only interesting tag just says its a multipolygon,
57380               // which is not descriptive enough
57381               // It's okay for a simple multipolygon to have no descriptive tags
57382               // if its outer way has them (old model, see `outdated_tags.js`)
57383               return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
57384             }
57385
57386             return entityDescriptiveKeys.length > 0;
57387           }
57388
57389           function isUnknownRoad(entity) {
57390             return entity.type === 'way' && entity.tags.highway === 'road';
57391           }
57392
57393           function isUntypedRelation(entity) {
57394             return entity.type === 'relation' && !entity.tags.type;
57395           }
57396
57397           var validation = function checkMissingTag(entity, graph) {
57398             var subtype;
57399             var osm = context.connection();
57400             var isUnloadedNode = entity.type === 'node' && osm && !osm.isDataLoaded(entity.loc); // we can't know if the node is a vertex if the tile is undownloaded
57401
57402             if (!isUnloadedNode && // allow untagged nodes that are part of ways
57403             entity.geometry(graph) !== 'vertex' && // allow untagged entities that are part of relations
57404             !entity.hasParentRelations(graph)) {
57405               if (Object.keys(entity.tags).length === 0) {
57406                 subtype = 'any';
57407               } else if (!hasDescriptiveTags(entity, graph)) {
57408                 subtype = 'descriptive';
57409               } else if (isUntypedRelation(entity)) {
57410                 subtype = 'relation_type';
57411               }
57412             } // flag an unknown road even if it's a member of a relation
57413
57414
57415             if (!subtype && isUnknownRoad(entity)) {
57416               subtype = 'highway_classification';
57417             }
57418
57419             if (!subtype) return [];
57420             var messageID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag.' + subtype;
57421             var referenceID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag'; // can always delete if the user created it in the first place..
57422
57423             var canDelete = entity.version === undefined || entity.v !== undefined;
57424             var severity = canDelete && subtype !== 'highway_classification' ? 'error' : 'warning';
57425             return [new validationIssue({
57426               type: type,
57427               subtype: subtype,
57428               severity: severity,
57429               message: function message(context) {
57430                 var entity = context.hasEntity(this.entityIds[0]);
57431                 return entity ? _t.html('issues.' + messageID + '.message', {
57432                   feature: utilDisplayLabel(entity, context.graph())
57433                 }) : '';
57434               },
57435               reference: showReference,
57436               entityIds: [entity.id],
57437               dynamicFixes: function dynamicFixes(context) {
57438                 var fixes = [];
57439                 var selectFixType = subtype === 'highway_classification' ? 'select_road_type' : 'select_preset';
57440                 fixes.push(new validationIssueFix({
57441                   icon: 'iD-icon-search',
57442                   title: _t.html('issues.fix.' + selectFixType + '.title'),
57443                   onClick: function onClick(context) {
57444                     context.ui().sidebar.showPresetList();
57445                   }
57446                 }));
57447                 var deleteOnClick;
57448                 var id = this.entityIds[0];
57449                 var operation = operationDelete(context, [id]);
57450                 var disabledReasonID = operation.disabled();
57451
57452                 if (!disabledReasonID) {
57453                   deleteOnClick = function deleteOnClick(context) {
57454                     var id = this.issue.entityIds[0];
57455                     var operation = operationDelete(context, [id]);
57456
57457                     if (!operation.disabled()) {
57458                       operation();
57459                     }
57460                   };
57461                 }
57462
57463                 fixes.push(new validationIssueFix({
57464                   icon: 'iD-operation-delete',
57465                   title: _t.html('issues.fix.delete_feature.title'),
57466                   disabledReason: disabledReasonID ? _t('operations.delete.' + disabledReasonID + '.single') : undefined,
57467                   onClick: deleteOnClick
57468                 }));
57469                 return fixes;
57470               }
57471             })];
57472
57473             function showReference(selection) {
57474               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.' + referenceID + '.reference'));
57475             }
57476           };
57477
57478           validation.type = type;
57479           return validation;
57480         }
57481
57482         function validationOutdatedTags() {
57483           var type = 'outdated_tags';
57484           var _waitingForDeprecated = true;
57485
57486           var _dataDeprecated; // fetch deprecated tags
57487
57488
57489           _mainFileFetcher.get('deprecated').then(function (d) {
57490             return _dataDeprecated = d;
57491           })["catch"](function () {
57492             /* ignore */
57493           })["finally"](function () {
57494             return _waitingForDeprecated = false;
57495           });
57496
57497           function oldTagIssues(entity, graph) {
57498             var oldTags = Object.assign({}, entity.tags); // shallow copy
57499
57500             var preset = _mainPresetIndex.match(entity, graph);
57501             var subtype = 'deprecated_tags';
57502             if (!preset) return [];
57503             if (!entity.hasInterestingTags()) return []; // Upgrade preset, if a replacement is available..
57504
57505             if (preset.replacement) {
57506               var newPreset = _mainPresetIndex.item(preset.replacement);
57507               graph = actionChangePreset(entity.id, preset, newPreset, true
57508               /* skip field defaults */
57509               )(graph);
57510               entity = graph.entity(entity.id);
57511               preset = newPreset;
57512             } // Upgrade deprecated tags..
57513
57514
57515             if (_dataDeprecated) {
57516               var deprecatedTags = entity.deprecatedTags(_dataDeprecated);
57517
57518               if (deprecatedTags.length) {
57519                 deprecatedTags.forEach(function (tag) {
57520                   graph = actionUpgradeTags(entity.id, tag.old, tag.replace)(graph);
57521                 });
57522                 entity = graph.entity(entity.id);
57523               }
57524             } // Add missing addTags from the detected preset
57525
57526
57527             var newTags = Object.assign({}, entity.tags); // shallow copy
57528
57529             if (preset.tags !== preset.addTags) {
57530               Object.keys(preset.addTags).forEach(function (k) {
57531                 if (!newTags[k]) {
57532                   if (preset.addTags[k] === '*') {
57533                     newTags[k] = 'yes';
57534                   } else {
57535                     newTags[k] = preset.addTags[k];
57536                   }
57537                 }
57538               });
57539             } // Attempt to match a canonical record in the name-suggestion-index.
57540
57541
57542             var nsi = services.nsi;
57543             var waitingForNsi = false;
57544
57545             if (nsi) {
57546               waitingForNsi = nsi.status() === 'loading';
57547
57548               if (!waitingForNsi) {
57549                 var loc = entity.extent(graph).center();
57550                 var result = nsi.upgradeTags(newTags, loc);
57551
57552                 if (result) {
57553                   newTags = result;
57554                   subtype = 'noncanonical_brand';
57555                 }
57556               }
57557             }
57558
57559             var issues = [];
57560             issues.provisional = _waitingForDeprecated || waitingForNsi; // determine diff
57561
57562             var tagDiff = utilTagDiff(oldTags, newTags);
57563             if (!tagDiff.length) return issues;
57564             var isOnlyAddingTags = tagDiff.every(function (d) {
57565               return d.type === '+';
57566             });
57567             var prefix = '';
57568
57569             if (subtype === 'noncanonical_brand') {
57570               prefix = 'noncanonical_brand.';
57571             } else if (subtype === 'deprecated_tags' && isOnlyAddingTags) {
57572               subtype = 'incomplete_tags';
57573               prefix = 'incomplete.';
57574             } // don't allow autofixing brand tags
57575
57576
57577             var autoArgs = subtype !== 'noncanonical_brand' ? [doUpgrade, _t('issues.fix.upgrade_tags.annotation')] : null;
57578             issues.push(new validationIssue({
57579               type: type,
57580               subtype: subtype,
57581               severity: 'warning',
57582               message: showMessage,
57583               reference: showReference,
57584               entityIds: [entity.id],
57585               hash: utilHashcode(JSON.stringify(tagDiff)),
57586               dynamicFixes: function dynamicFixes() {
57587                 return [new validationIssueFix({
57588                   autoArgs: autoArgs,
57589                   title: _t.html('issues.fix.upgrade_tags.title'),
57590                   onClick: function onClick(context) {
57591                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
57592                   }
57593                 })];
57594               }
57595             }));
57596             return issues;
57597
57598             function doUpgrade(graph) {
57599               var currEntity = graph.hasEntity(entity.id);
57600               if (!currEntity) return graph;
57601               var newTags = Object.assign({}, currEntity.tags); // shallow copy
57602
57603               tagDiff.forEach(function (diff) {
57604                 if (diff.type === '-') {
57605                   delete newTags[diff.key];
57606                 } else if (diff.type === '+') {
57607                   newTags[diff.key] = diff.newVal;
57608                 }
57609               });
57610               return actionChangeTags(currEntity.id, newTags)(graph);
57611             }
57612
57613             function showMessage(context) {
57614               var currEntity = context.hasEntity(entity.id);
57615               if (!currEntity) return '';
57616               var messageID = "issues.outdated_tags.".concat(prefix, "message");
57617
57618               if (subtype === 'noncanonical_brand' && isOnlyAddingTags) {
57619                 messageID += '_incomplete';
57620               }
57621
57622               return _t.html(messageID, {
57623                 feature: utilDisplayLabel(currEntity, context.graph(), true
57624                 /* verbose */
57625                 )
57626               });
57627             }
57628
57629             function showReference(selection) {
57630               var enter = selection.selectAll('.issue-reference').data([0]).enter();
57631               enter.append('div').attr('class', 'issue-reference').html(_t.html("issues.outdated_tags.".concat(prefix, "reference")));
57632               enter.append('strong').html(_t.html('issues.suggested'));
57633               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) {
57634                 var klass = d.type === '+' ? 'add' : 'remove';
57635                 return "tagDiff-cell tagDiff-cell-".concat(klass);
57636               }).html(function (d) {
57637                 return d.display;
57638               });
57639             }
57640           }
57641
57642           function oldMultipolygonIssues(entity, graph) {
57643             var multipolygon, outerWay;
57644
57645             if (entity.type === 'relation') {
57646               outerWay = osmOldMultipolygonOuterMemberOfRelation(entity, graph);
57647               multipolygon = entity;
57648             } else if (entity.type === 'way') {
57649               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
57650               outerWay = entity;
57651             } else {
57652               return [];
57653             }
57654
57655             if (!multipolygon || !outerWay) return [];
57656             return [new validationIssue({
57657               type: type,
57658               subtype: 'old_multipolygon',
57659               severity: 'warning',
57660               message: showMessage,
57661               reference: showReference,
57662               entityIds: [outerWay.id, multipolygon.id],
57663               dynamicFixes: function dynamicFixes() {
57664                 return [new validationIssueFix({
57665                   autoArgs: [doUpgrade, _t('issues.fix.move_tags.annotation')],
57666                   title: _t.html('issues.fix.move_tags.title'),
57667                   onClick: function onClick(context) {
57668                     context.perform(doUpgrade, _t('issues.fix.move_tags.annotation'));
57669                   }
57670                 })];
57671               }
57672             })];
57673
57674             function doUpgrade(graph) {
57675               var currMultipolygon = graph.hasEntity(multipolygon.id);
57676               var currOuterWay = graph.hasEntity(outerWay.id);
57677               if (!currMultipolygon || !currOuterWay) return graph;
57678               currMultipolygon = currMultipolygon.mergeTags(currOuterWay.tags);
57679               graph = graph.replace(currMultipolygon);
57680               return actionChangeTags(currOuterWay.id, {})(graph);
57681             }
57682
57683             function showMessage(context) {
57684               var currMultipolygon = context.hasEntity(multipolygon.id);
57685               if (!currMultipolygon) return '';
57686               return _t.html('issues.old_multipolygon.message', {
57687                 multipolygon: utilDisplayLabel(currMultipolygon, context.graph(), true
57688                 /* verbose */
57689                 )
57690               });
57691             }
57692
57693             function showReference(selection) {
57694               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.old_multipolygon.reference'));
57695             }
57696           }
57697
57698           var validation = function checkOutdatedTags(entity, graph) {
57699             var issues = oldMultipolygonIssues(entity, graph);
57700             if (!issues.length) issues = oldTagIssues(entity, graph);
57701             return issues;
57702           };
57703
57704           validation.type = type;
57705           return validation;
57706         }
57707
57708         function validationPrivateData() {
57709           var type = 'private_data'; // assume that some buildings are private
57710
57711           var privateBuildingValues = {
57712             detached: true,
57713             farm: true,
57714             house: true,
57715             houseboat: true,
57716             residential: true,
57717             semidetached_house: true,
57718             static_caravan: true
57719           }; // but they might be public if they have one of these other tags
57720
57721           var publicKeys = {
57722             amenity: true,
57723             craft: true,
57724             historic: true,
57725             leisure: true,
57726             office: true,
57727             shop: true,
57728             tourism: true
57729           }; // these tags may contain personally identifying info
57730
57731           var personalTags = {
57732             'contact:email': true,
57733             'contact:fax': true,
57734             'contact:phone': true,
57735             email: true,
57736             fax: true,
57737             phone: true
57738           };
57739
57740           var validation = function checkPrivateData(entity) {
57741             var tags = entity.tags;
57742             if (!tags.building || !privateBuildingValues[tags.building]) return [];
57743             var keepTags = {};
57744
57745             for (var k in tags) {
57746               if (publicKeys[k]) return []; // probably a public feature
57747
57748               if (!personalTags[k]) {
57749                 keepTags[k] = tags[k];
57750               }
57751             }
57752
57753             var tagDiff = utilTagDiff(tags, keepTags);
57754             if (!tagDiff.length) return [];
57755             var fixID = tagDiff.length === 1 ? 'remove_tag' : 'remove_tags';
57756             return [new validationIssue({
57757               type: type,
57758               severity: 'warning',
57759               message: showMessage,
57760               reference: showReference,
57761               entityIds: [entity.id],
57762               dynamicFixes: function dynamicFixes() {
57763                 return [new validationIssueFix({
57764                   icon: 'iD-operation-delete',
57765                   title: _t.html('issues.fix.' + fixID + '.title'),
57766                   onClick: function onClick(context) {
57767                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
57768                   }
57769                 })];
57770               }
57771             })];
57772
57773             function doUpgrade(graph) {
57774               var currEntity = graph.hasEntity(entity.id);
57775               if (!currEntity) return graph;
57776               var newTags = Object.assign({}, currEntity.tags); // shallow copy
57777
57778               tagDiff.forEach(function (diff) {
57779                 if (diff.type === '-') {
57780                   delete newTags[diff.key];
57781                 } else if (diff.type === '+') {
57782                   newTags[diff.key] = diff.newVal;
57783                 }
57784               });
57785               return actionChangeTags(currEntity.id, newTags)(graph);
57786             }
57787
57788             function showMessage(context) {
57789               var currEntity = context.hasEntity(this.entityIds[0]);
57790               if (!currEntity) return '';
57791               return _t.html('issues.private_data.contact.message', {
57792                 feature: utilDisplayLabel(currEntity, context.graph())
57793               });
57794             }
57795
57796             function showReference(selection) {
57797               var enter = selection.selectAll('.issue-reference').data([0]).enter();
57798               enter.append('div').attr('class', 'issue-reference').html(_t.html('issues.private_data.reference'));
57799               enter.append('strong').html(_t.html('issues.suggested'));
57800               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) {
57801                 var klass = d.type === '+' ? 'add' : 'remove';
57802                 return 'tagDiff-cell tagDiff-cell-' + klass;
57803               }).html(function (d) {
57804                 return d.display;
57805               });
57806             }
57807           };
57808
57809           validation.type = type;
57810           return validation;
57811         }
57812
57813         function validationSuspiciousName() {
57814           var type = 'suspicious_name';
57815           var keysToTestForGenericValues = ['aerialway', 'aeroway', 'amenity', 'building', 'craft', 'highway', 'leisure', 'railway', 'man_made', 'office', 'shop', 'tourism', 'waterway'];
57816           var _waitingForNsi = false; // Attempt to match a generic record in the name-suggestion-index.
57817
57818           function isGenericMatchInNsi(tags) {
57819             var nsi = services.nsi;
57820
57821             if (nsi) {
57822               _waitingForNsi = nsi.status() === 'loading';
57823
57824               if (!_waitingForNsi) {
57825                 return nsi.isGenericName(tags);
57826               }
57827             }
57828
57829             return false;
57830           } // Test if the name is just the key or tag value (e.g. "park")
57831
57832
57833           function nameMatchesRawTag(lowercaseName, tags) {
57834             for (var i = 0; i < keysToTestForGenericValues.length; i++) {
57835               var key = keysToTestForGenericValues[i];
57836               var val = tags[key];
57837
57838               if (val) {
57839                 val = val.toLowerCase();
57840
57841                 if (key === lowercaseName || val === lowercaseName || key.replace(/\_/g, ' ') === lowercaseName || val.replace(/\_/g, ' ') === lowercaseName) {
57842                   return true;
57843                 }
57844               }
57845             }
57846
57847             return false;
57848           }
57849
57850           function isGenericName(name, tags) {
57851             name = name.toLowerCase();
57852             return nameMatchesRawTag(name, tags) || isGenericMatchInNsi(tags);
57853           }
57854
57855           function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
57856             return new validationIssue({
57857               type: type,
57858               subtype: 'generic_name',
57859               severity: 'warning',
57860               message: function message(context) {
57861                 var entity = context.hasEntity(this.entityIds[0]);
57862                 if (!entity) return '';
57863                 var preset = _mainPresetIndex.match(entity, context.graph());
57864                 var langName = langCode && _mainLocalizer.languageName(langCode);
57865                 return _t.html('issues.generic_name.message' + (langName ? '_language' : ''), {
57866                   feature: preset.name(),
57867                   name: genericName,
57868                   language: langName
57869                 });
57870               },
57871               reference: showReference,
57872               entityIds: [entityId],
57873               hash: "".concat(nameKey, "=").concat(genericName),
57874               dynamicFixes: function dynamicFixes() {
57875                 return [new validationIssueFix({
57876                   icon: 'iD-operation-delete',
57877                   title: _t.html('issues.fix.remove_the_name.title'),
57878                   onClick: function onClick(context) {
57879                     var entityId = this.issue.entityIds[0];
57880                     var entity = context.entity(entityId);
57881                     var tags = Object.assign({}, entity.tags); // shallow copy
57882
57883                     delete tags[nameKey];
57884                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_generic_name.annotation'));
57885                   }
57886                 })];
57887               }
57888             });
57889
57890             function showReference(selection) {
57891               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
57892             }
57893           }
57894
57895           function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
57896             return new validationIssue({
57897               type: type,
57898               subtype: 'not_name',
57899               severity: 'warning',
57900               message: function message(context) {
57901                 var entity = context.hasEntity(this.entityIds[0]);
57902                 if (!entity) return '';
57903                 var preset = _mainPresetIndex.match(entity, context.graph());
57904                 var langName = langCode && _mainLocalizer.languageName(langCode);
57905                 return _t.html('issues.incorrect_name.message' + (langName ? '_language' : ''), {
57906                   feature: preset.name(),
57907                   name: incorrectName,
57908                   language: langName
57909                 });
57910               },
57911               reference: showReference,
57912               entityIds: [entityId],
57913               hash: "".concat(nameKey, "=").concat(incorrectName),
57914               dynamicFixes: function dynamicFixes() {
57915                 return [new validationIssueFix({
57916                   icon: 'iD-operation-delete',
57917                   title: _t.html('issues.fix.remove_the_name.title'),
57918                   onClick: function onClick(context) {
57919                     var entityId = this.issue.entityIds[0];
57920                     var entity = context.entity(entityId);
57921                     var tags = Object.assign({}, entity.tags); // shallow copy
57922
57923                     delete tags[nameKey];
57924                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_mistaken_name.annotation'));
57925                   }
57926                 })];
57927               }
57928             });
57929
57930             function showReference(selection) {
57931               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
57932             }
57933           }
57934
57935           var validation = function checkGenericName(entity) {
57936             var tags = entity.tags; // a generic name is allowed if it's a known brand or entity
57937
57938             var hasWikidata = !!tags.wikidata || !!tags['brand:wikidata'] || !!tags['operator:wikidata'];
57939             if (hasWikidata) return [];
57940             var issues = [];
57941             var notNames = (tags['not:name'] || '').split(';');
57942
57943             for (var key in tags) {
57944               var m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
57945               if (!m) continue;
57946               var langCode = m.length >= 2 ? m[1] : null;
57947               var value = tags[key];
57948
57949               if (notNames.length) {
57950                 for (var i in notNames) {
57951                   var notName = notNames[i];
57952
57953                   if (notName && value === notName) {
57954                     issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
57955                     continue;
57956                   }
57957                 }
57958               }
57959
57960               if (isGenericName(value, tags)) {
57961                 issues.provisional = _waitingForNsi; // retry later if we are waiting on NSI to finish loading
57962
57963                 issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
57964               }
57965             }
57966
57967             return issues;
57968           };
57969
57970           validation.type = type;
57971           return validation;
57972         }
57973
57974         function validationUnsquareWay(context) {
57975           var type = 'unsquare_way';
57976           var DEFAULT_DEG_THRESHOLD = 5; // see also issues.js
57977           // use looser epsilon for detection to reduce warnings of buildings that are essentially square already
57978
57979           var epsilon = 0.05;
57980           var nodeThreshold = 10;
57981
57982           function isBuilding(entity, graph) {
57983             if (entity.type !== 'way' || entity.geometry(graph) !== 'area') return false;
57984             return entity.tags.building && entity.tags.building !== 'no';
57985           }
57986
57987           var validation = function checkUnsquareWay(entity, graph) {
57988             if (!isBuilding(entity, graph)) return []; // don't flag ways marked as physically unsquare
57989
57990             if (entity.tags.nonsquare === 'yes') return [];
57991             var isClosed = entity.isClosed();
57992             if (!isClosed) return []; // this building has bigger problems
57993             // don't flag ways with lots of nodes since they are likely detail-mapped
57994
57995             var nodes = graph.childNodes(entity).slice(); // shallow copy
57996
57997             if (nodes.length > nodeThreshold + 1) return []; // +1 because closing node appears twice
57998             // ignore if not all nodes are fully downloaded
57999
58000             var osm = services.osm;
58001             if (!osm || nodes.some(function (node) {
58002               return !osm.isDataLoaded(node.loc);
58003             })) return []; // don't flag connected ways to avoid unresolvable unsquare loops
58004
58005             var hasConnectedSquarableWays = nodes.some(function (node) {
58006               return graph.parentWays(node).some(function (way) {
58007                 if (way.id === entity.id) return false;
58008                 if (isBuilding(way, graph)) return true;
58009                 return graph.parentRelations(way).some(function (parentRelation) {
58010                   return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== 'no';
58011                 });
58012               });
58013             });
58014             if (hasConnectedSquarableWays) return []; // user-configurable square threshold
58015
58016             var storedDegreeThreshold = corePreferences('validate-square-degrees');
58017             var degreeThreshold = isNaN(storedDegreeThreshold) ? DEFAULT_DEG_THRESHOLD : parseFloat(storedDegreeThreshold);
58018             var points = nodes.map(function (node) {
58019               return context.projection(node.loc);
58020             });
58021             if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon, degreeThreshold, true)) return [];
58022             var autoArgs; // don't allow autosquaring features linked to wikidata
58023
58024             if (!entity.tags.wikidata) {
58025               // use same degree threshold as for detection
58026               var autoAction = actionOrthogonalize(entity.id, context.projection, undefined, degreeThreshold);
58027               autoAction.transitionable = false; // when autofixing, do it instantly
58028
58029               autoArgs = [autoAction, _t('operations.orthogonalize.annotation.feature', {
58030                 n: 1
58031               })];
58032             }
58033
58034             return [new validationIssue({
58035               type: type,
58036               subtype: 'building',
58037               severity: 'warning',
58038               message: function message(context) {
58039                 var entity = context.hasEntity(this.entityIds[0]);
58040                 return entity ? _t.html('issues.unsquare_way.message', {
58041                   feature: utilDisplayLabel(entity, context.graph())
58042                 }) : '';
58043               },
58044               reference: showReference,
58045               entityIds: [entity.id],
58046               hash: degreeThreshold,
58047               dynamicFixes: function dynamicFixes() {
58048                 return [new validationIssueFix({
58049                   icon: 'iD-operation-orthogonalize',
58050                   title: _t.html('issues.fix.square_feature.title'),
58051                   autoArgs: autoArgs,
58052                   onClick: function onClick(context, completionHandler) {
58053                     var entityId = this.issue.entityIds[0]; // use same degree threshold as for detection
58054
58055                     context.perform(actionOrthogonalize(entityId, context.projection, undefined, degreeThreshold), _t('operations.orthogonalize.annotation.feature', {
58056                       n: 1
58057                     })); // run after the squaring transition (currently 150ms)
58058
58059                     window.setTimeout(function () {
58060                       completionHandler();
58061                     }, 175);
58062                   }
58063                 })
58064                 /*
58065                 new validationIssueFix({
58066                     title: t.html('issues.fix.tag_as_unsquare.title'),
58067                     onClick: function(context) {
58068                         var entityId = this.issue.entityIds[0];
58069                         var entity = context.entity(entityId);
58070                         var tags = Object.assign({}, entity.tags);  // shallow copy
58071                         tags.nonsquare = 'yes';
58072                         context.perform(
58073                             actionChangeTags(entityId, tags),
58074                             t('issues.fix.tag_as_unsquare.annotation')
58075                         );
58076                     }
58077                 })
58078                 */
58079                 ];
58080               }
58081             })];
58082
58083             function showReference(selection) {
58084               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unsquare_way.buildings.reference'));
58085             }
58086           };
58087
58088           validation.type = type;
58089           return validation;
58090         }
58091
58092         var Validations = /*#__PURE__*/Object.freeze({
58093                 __proto__: null,
58094                 validationAlmostJunction: validationAlmostJunction,
58095                 validationCloseNodes: validationCloseNodes,
58096                 validationCrossingWays: validationCrossingWays,
58097                 validationDisconnectedWay: validationDisconnectedWay,
58098                 validationFormatting: validationFormatting,
58099                 validationHelpRequest: validationHelpRequest,
58100                 validationImpossibleOneway: validationImpossibleOneway,
58101                 validationIncompatibleSource: validationIncompatibleSource,
58102                 validationMaprules: validationMaprules,
58103                 validationMismatchedGeometry: validationMismatchedGeometry,
58104                 validationMissingRole: validationMissingRole,
58105                 validationMissingTag: validationMissingTag,
58106                 validationOutdatedTags: validationOutdatedTags,
58107                 validationPrivateData: validationPrivateData,
58108                 validationSuspiciousName: validationSuspiciousName,
58109                 validationUnsquareWay: validationUnsquareWay
58110         });
58111
58112         function coreValidator(context) {
58113           var _this = this;
58114
58115           var dispatch = dispatch$8('validated', 'focusedIssue');
58116           var validator = utilRebind({}, dispatch, 'on');
58117           var _rules = {};
58118           var _disabledRules = {};
58119
58120           var _ignoredIssueIDs = new Set();
58121
58122           var _resolvedIssueIDs = new Set();
58123
58124           var _baseCache = validationCache(); // issues before any user edits
58125
58126
58127           var _headCache = validationCache(); // issues after all user edits
58128
58129
58130           var _headGraph = null;
58131           var _headIsCurrent = false;
58132
58133           var _deferredRIC = new Set(); // Set( RequestIdleCallback handles )
58134
58135
58136           var _deferredST = new Set(); // Set( SetTimeout handles )
58137
58138
58139           var _headPromise; // Promise fulfilled when validation is performed up to headGraph snapshot
58140
58141
58142           var RETRY = 5000; // wait 5sec before revalidating provisional entities
58143           // Allow validation severity to be overridden by url queryparams...
58144           // Each param should contain a urlencoded comma separated list of
58145           // `type/subtype` rules.  `*` may be used as a wildcard..
58146           // Examples:
58147           //  `validationError=disconnected_way/*`
58148           //  `validationError=disconnected_way/highway`
58149           //  `validationError=crossing_ways/bridge*`
58150           //  `validationError=crossing_ways/bridge*,crossing_ways/tunnel*`
58151
58152           var _errorOverrides = parseHashParam(context.initialHashParams.validationError);
58153
58154           var _warningOverrides = parseHashParam(context.initialHashParams.validationWarning);
58155
58156           var _disableOverrides = parseHashParam(context.initialHashParams.validationDisable);
58157
58158           function parseHashParam(param) {
58159             var result = [];
58160             var rules = (param || '').split(',');
58161             rules.forEach(function (rule) {
58162               rule = rule.trim();
58163               var parts = rule.split('/', 2); // "type/subtype"
58164
58165               var type = parts[0];
58166               var subtype = parts[1] || '*';
58167               if (!type || !subtype) return;
58168               result.push({
58169                 type: makeRegExp(type),
58170                 subtype: makeRegExp(subtype)
58171               });
58172             });
58173             return result;
58174           }
58175
58176           function makeRegExp(str) {
58177             var escaped = str.replace(/[-\/\\^$+?.()|[\]{}]/g, '\\$&') // escape all reserved chars except for the '*'
58178             .replace(/\*/g, '.*'); // treat a '*' like '.*'
58179
58180             return new RegExp('^' + escaped + '$');
58181           } // `init()`
58182           // Initialize the validator, called once on iD startup
58183           //
58184
58185
58186           validator.init = function () {
58187             Object.values(Validations).forEach(function (validation) {
58188               if (typeof validation !== 'function') return;
58189               var fn = validation(context);
58190               var key = fn.type;
58191               _rules[key] = fn;
58192             });
58193             var disabledRules = corePreferences('validate-disabledRules');
58194
58195             if (disabledRules) {
58196               disabledRules.split(',').forEach(function (k) {
58197                 return _disabledRules[k] = true;
58198               });
58199             }
58200           }; // `reset()`   (private)
58201           // Cancels deferred work and resets all caches
58202           //
58203           // Arguments
58204           //   `resetIgnored` - `true` to clear the list of user-ignored issues
58205           //
58206
58207
58208           function reset(resetIgnored) {
58209             // cancel deferred work
58210             _deferredRIC.forEach(window.cancelIdleCallback);
58211
58212             _deferredRIC.clear();
58213
58214             _deferredST.forEach(window.clearTimeout);
58215
58216             _deferredST.clear(); // empty queues and resolve any pending promise
58217
58218
58219             _baseCache.queue = [];
58220             _headCache.queue = [];
58221             processQueue(_headCache);
58222             processQueue(_baseCache); // clear caches
58223
58224             if (resetIgnored) _ignoredIssueIDs.clear();
58225
58226             _resolvedIssueIDs.clear();
58227
58228             _baseCache = validationCache();
58229             _headCache = validationCache();
58230             _headGraph = null;
58231             _headIsCurrent = false;
58232           } // `reset()`
58233           // clear caches, called whenever iD resets after a save or switches sources
58234           // (clears out the _ignoredIssueIDs set also)
58235           //
58236
58237
58238           validator.reset = function () {
58239             reset(true);
58240           }; // `resetIgnoredIssues()`
58241           // clears out the _ignoredIssueIDs Set
58242           //
58243
58244
58245           validator.resetIgnoredIssues = function () {
58246             _ignoredIssueIDs.clear();
58247
58248             dispatch.call('validated'); // redraw UI
58249           }; // `revalidateUnsquare()`
58250           // Called whenever the user changes the unsquare threshold
58251           // It reruns just the "unsquare_way" validation on all buildings.
58252           //
58253
58254
58255           validator.revalidateUnsquare = function () {
58256             revalidateUnsquare(_headCache, _headGraph);
58257             revalidateUnsquare(_baseCache, context.history().base());
58258             dispatch.call('validated');
58259           };
58260
58261           function revalidateUnsquare(cache, graph) {
58262             var checkUnsquareWay = _rules.unsquare_way;
58263             if (!graph || typeof checkUnsquareWay !== 'function') return; // uncache existing
58264
58265             cache.uncacheIssuesOfType('unsquare_way');
58266             var buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), graph) // everywhere
58267             .filter(function (entity) {
58268               return entity.type === 'way' && entity.tags.building && entity.tags.building !== 'no';
58269             }); // rerun for all buildings
58270
58271             buildings.forEach(function (entity) {
58272               var detected = checkUnsquareWay(entity, graph);
58273               if (!detected.length) return;
58274               cache.cacheIssues(detected);
58275             });
58276           } // `getIssues()`
58277           // Gets all issues that match the given options
58278           // This is called by many other places
58279           //
58280           // Arguments
58281           //   `options` Object like:
58282           //   {
58283           //     what: 'all',                  // 'all' or 'edited'
58284           //     where: 'all',                 // 'all' or 'visible'
58285           //     includeIgnored: false,        // true, false, or 'only'
58286           //     includeDisabledRules: false   // true, false, or 'only'
58287           //   }
58288           //
58289           // Returns
58290           //   An Array containing the issues
58291           //
58292
58293
58294           validator.getIssues = function (options) {
58295             var opts = Object.assign({
58296               what: 'all',
58297               where: 'all',
58298               includeIgnored: false,
58299               includeDisabledRules: false
58300             }, options);
58301             var view = context.map().extent();
58302             var issues = [];
58303             var seen = new Set(); // collect head issues - caused by user edits
58304
58305             var cache = _headCache;
58306
58307             if (_headGraph) {
58308               Object.values(cache.issuesByIssueID).forEach(function (issue) {
58309                 if (!filter(issue, _headGraph, cache)) return;
58310                 seen.add(issue.id);
58311                 issues.push(issue);
58312               });
58313             } // collect base issues - not caused by user edits
58314
58315
58316             if (opts.what === 'all') {
58317               cache = _baseCache;
58318               Object.values(cache.issuesByIssueID).forEach(function (issue) {
58319                 if (!filter(issue, context.history().base(), cache)) return;
58320                 seen.add(issue.id);
58321                 issues.push(issue);
58322               });
58323             }
58324
58325             return issues;
58326
58327             function filter(issue, resolver, cache) {
58328               if (!issue) return false;
58329               if (seen.has(issue.id)) return false;
58330               if (_resolvedIssueIDs.has(issue.id)) return false;
58331               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
58332               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
58333               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs.has(issue.id)) return false;
58334               if (!opts.includeIgnored && _ignoredIssueIDs.has(issue.id)) return false; // Sanity check:  This issue may be for an entity that not longer exists.
58335               // If we detect this, uncache and return false so it is not included..
58336
58337               var entityIDs = issue.entityIds || [];
58338
58339               for (var i = 0; i < entityIDs.length; i++) {
58340                 var entityID = entityIDs[i];
58341
58342                 if (!resolver.hasEntity(entityID)) {
58343                   cache.uncacheEntityID(entityID);
58344                   return false;
58345                 }
58346               }
58347
58348               if (opts.where === 'visible') {
58349                 var extent = issue.extent(resolver);
58350                 if (!view.intersects(extent)) return false;
58351               }
58352
58353               return true;
58354             }
58355           }; // `getResolvedIssues()`
58356           // Gets the issues that have been fixed by the user.
58357           // Resolved issues are tracked in the `_resolvedIssueIDs` Set
58358           //
58359           // Returns
58360           //   An Array containing the issues
58361           //
58362
58363
58364           validator.getResolvedIssues = function () {
58365             var collected = new Set();
58366             Object.values(_baseCache.issuesByIssueID).forEach(function (issue) {
58367               if (_resolvedIssueIDs.has(issue.id)) collected.add(issue);
58368             });
58369             Object.values(_headCache.issuesByIssueID).forEach(function (issue) {
58370               if (_resolvedIssueIDs.has(issue.id)) collected.add(issue);
58371             });
58372             return Array.from(collected);
58373           }; // `focusIssue()`
58374           // Adjusts the map to focus on the given issue.
58375           // (requires the issue to have a reasonable extent defined)
58376           //
58377           // Arguments
58378           //   `issue` - the issue to focus on
58379           //
58380
58381
58382           validator.focusIssue = function (issue) {
58383             var extent = issue.extent(context.graph());
58384             if (!extent) return;
58385             var setZoom = Math.max(context.map().zoom(), 19);
58386             context.map().unobscuredCenterZoomEase(extent.center(), setZoom); // select the first entity
58387
58388             if (issue.entityIds && issue.entityIds.length) {
58389               window.setTimeout(function () {
58390                 var ids = issue.entityIds;
58391                 context.enter(modeSelect(context, [ids[0]]));
58392                 dispatch.call('focusedIssue', _this, issue);
58393               }, 250); // after ease
58394             }
58395           }; // `getIssuesBySeverity()`
58396           // Gets the issues then groups them by error/warning
58397           // (This just calls getIssues, then puts issues in groups)
58398           //
58399           // Arguments
58400           //   `options` - (see `getIssues`)
58401           // Returns
58402           //   Object result like:
58403           //   {
58404           //     error:    Array of errors,
58405           //     warning:  Array of warnings
58406           //   }
58407           //
58408
58409
58410           validator.getIssuesBySeverity = function (options) {
58411             var groups = utilArrayGroupBy(validator.getIssues(options), 'severity');
58412             groups.error = groups.error || [];
58413             groups.warning = groups.warning || [];
58414             return groups;
58415           }; // `getEntityIssues()`
58416           // Gets the issues that the given entity IDs have in common, matching the given options
58417           // (This just calls getIssues, then filters for the given entity IDs)
58418           // The issues are sorted for relevance
58419           //
58420           // Arguments
58421           //   `entityIDs` - Array or Set of entityIDs to get issues for
58422           //   `options` - (see `getIssues`)
58423           // Returns
58424           //   An Array containing the issues
58425           //
58426
58427
58428           validator.getSharedEntityIssues = function (entityIDs, options) {
58429             // show some issue types in a particular order
58430             var orderedIssueTypes = [// flag missing data first
58431             'missing_tag', 'missing_role', // then flag identity issues
58432             'outdated_tags', 'mismatched_geometry', // flag geometry issues where fixing them might solve connectivity issues
58433             'crossing_ways', 'almost_junction', // then flag connectivity issues
58434             'disconnected_way', 'impossible_oneway'];
58435             var allIssues = validator.getIssues(options);
58436             var forEntityIDs = new Set(entityIDs);
58437             return allIssues.filter(function (issue) {
58438               return (issue.entityIds || []).some(function (entityID) {
58439                 return forEntityIDs.has(entityID);
58440               });
58441             }).sort(function (issue1, issue2) {
58442               if (issue1.type === issue2.type) {
58443                 // issues of the same type, sort deterministically
58444                 return issue1.id < issue2.id ? -1 : 1;
58445               }
58446
58447               var index1 = orderedIssueTypes.indexOf(issue1.type);
58448               var index2 = orderedIssueTypes.indexOf(issue2.type);
58449
58450               if (index1 !== -1 && index2 !== -1) {
58451                 // both issue types have explicit sort orders
58452                 return index1 - index2;
58453               } else if (index1 === -1 && index2 === -1) {
58454                 // neither issue type has an explicit sort order, sort by type
58455                 return issue1.type < issue2.type ? -1 : 1;
58456               } else {
58457                 // order explicit types before everything else
58458                 return index1 !== -1 ? -1 : 1;
58459               }
58460             });
58461           }; // `getEntityIssues()`
58462           // Get an array of detected issues for the given entityID.
58463           // (This just calls getSharedEntityIssues for a single entity)
58464           //
58465           // Arguments
58466           //   `entityID` - the entity ID to get the issues for
58467           //   `options` - (see `getIssues`)
58468           // Returns
58469           //   An Array containing the issues
58470           //
58471
58472
58473           validator.getEntityIssues = function (entityID, options) {
58474             return validator.getSharedEntityIssues([entityID], options);
58475           }; // `getRuleKeys()`
58476           //
58477           // Returns
58478           //   An Array containing the rule keys
58479           //
58480
58481
58482           validator.getRuleKeys = function () {
58483             return Object.keys(_rules);
58484           }; // `isRuleEnabled()`
58485           //
58486           // Arguments
58487           //   `key` - the rule to check (e.g. 'crossing_ways')
58488           // Returns
58489           //   `true`/`false`
58490           //
58491
58492
58493           validator.isRuleEnabled = function (key) {
58494             return !_disabledRules[key];
58495           }; // `toggleRule()`
58496           // Toggles a single validation rule,
58497           // then reruns the validation so that the user sees something happen in the UI
58498           //
58499           // Arguments
58500           //   `key` - the rule to toggle (e.g. 'crossing_ways')
58501           //
58502
58503
58504           validator.toggleRule = function (key) {
58505             if (_disabledRules[key]) {
58506               delete _disabledRules[key];
58507             } else {
58508               _disabledRules[key] = true;
58509             }
58510
58511             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
58512             validator.validate();
58513           }; // `disableRules()`
58514           // Disables given validation rules,
58515           // then reruns the validation so that the user sees something happen in the UI
58516           //
58517           // Arguments
58518           //   `keys` - Array or Set containing rule keys to disable
58519           //
58520
58521
58522           validator.disableRules = function (keys) {
58523             _disabledRules = {};
58524             keys.forEach(function (k) {
58525               return _disabledRules[k] = true;
58526             });
58527             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
58528             validator.validate();
58529           }; // `ignoreIssue()`
58530           // Don't show the given issue in lists
58531           //
58532           // Arguments
58533           //   `issueID` - the issueID
58534           //
58535
58536
58537           validator.ignoreIssue = function (issueID) {
58538             _ignoredIssueIDs.add(issueID);
58539           }; // `validate()`
58540           // Validates anything that has changed in the head graph since the last time it was run.
58541           // (head graph contains user's edits)
58542           //
58543           // Returns
58544           //   A Promise fulfilled when the validation has completed and then dispatches a `validated` event.
58545           //   This may take time but happen in the background during browser idle time.
58546           //
58547
58548
58549           validator.validate = function () {
58550             var currGraph = context.graph();
58551
58552             var prevGraph = _headGraph || context.history().base();
58553
58554             if (currGraph === prevGraph) {
58555               // _headGraph is current - we are caught up
58556               _headIsCurrent = true;
58557               dispatch.call('validated');
58558               return Promise.resolve();
58559             }
58560
58561             if (_headPromise) {
58562               // Validation already in process, but we aren't caught up to current
58563               _headIsCurrent = false; // We will need to catch up after the validation promise fulfills
58564
58565               return _headPromise;
58566             }
58567
58568             _headGraph = currGraph; // take snapshot
58569
58570             var difference = coreDifference(prevGraph, _headGraph); // Gather all entities related to this difference..
58571             // For created/modified, use the head graph
58572
58573             var entityIDs = difference.extantIDs(true); // created/modified (true = w/relation members)
58574
58575             entityIDs = entityIDsToValidate(entityIDs, _headGraph); // For modified/deleted, use the previous graph
58576             // (e.g. deleting the only highway connected to a road should create a disconnected highway issue)
58577
58578             var previousEntityIDs = difference.deleted().concat(difference.modified()).map(function (entity) {
58579               return entity.id;
58580             });
58581             previousEntityIDs = entityIDsToValidate(previousEntityIDs, prevGraph);
58582             previousEntityIDs.forEach(entityIDs.add, entityIDs); // concat the sets
58583
58584             if (!entityIDs.size) {
58585               dispatch.call('validated');
58586               return Promise.resolve();
58587             }
58588
58589             _headPromise = validateEntitiesAsync(entityIDs, _headGraph, _headCache).then(function () {
58590               return updateResolvedIssues(entityIDs);
58591             }).then(function () {
58592               return dispatch.call('validated');
58593             })["catch"](function () {
58594               /* ignore */
58595             }).then(function () {
58596               _headPromise = null;
58597
58598               if (!_headIsCurrent) {
58599                 validator.validate(); // run it again to catch up to current graph
58600               }
58601             });
58602             return _headPromise;
58603           }; // register event handlers:
58604           // WHEN TO RUN VALIDATION:
58605           // When history changes:
58606
58607
58608           context.history().on('restore.validator', validator.validate) // on restore saved history
58609           .on('undone.validator', validator.validate) // on undo
58610           .on('redone.validator', validator.validate) // on redo
58611           .on('reset.validator', function () {
58612             // on history reset - happens after save, or enter/exit walkthrough
58613             reset(false); // cached issues aren't valid any longer if the history has been reset
58614
58615             validator.validate();
58616           }); // but not on 'change' (e.g. while drawing)
58617           // When user changes editing modes (to catch recent changes e.g. drawing)
58618
58619           context.on('exit.validator', validator.validate); // When merging fetched data, validate base graph:
58620
58621           context.history().on('merge.validator', function (entities) {
58622             if (!entities) return;
58623             var baseGraph = context.history().base();
58624             var entityIDs = entities.map(function (entity) {
58625               return entity.id;
58626             });
58627             entityIDs = entityIDsToValidate(entityIDs, baseGraph);
58628             validateEntitiesAsync(entityIDs, baseGraph, _baseCache);
58629           }); // `validateEntity()`   (private)
58630           // Runs all validation rules on a single entity.
58631           // Some things to note:
58632           //  - Graph is passed in from whenever the validation was started.  Validators shouldn't use
58633           //   `context.graph()` because this all happens async, and the graph might have changed
58634           //   (for example, nodes getting deleted before the validation can run)
58635           //  - Validator functions may still be waiting on something and return a "provisional" result.
58636           //    In this situation, we will schedule to revalidate the entity sometime later.
58637           //
58638           // Arguments
58639           //   `entity` - The entity
58640           //   `graph` - graph containing the entity
58641           //
58642           // Returns
58643           //   Object result like:
58644           //   {
58645           //     issues:       Array of detected issues
58646           //     provisional:  `true` if provisional result, `false` if final result
58647           //   }
58648           //
58649
58650           function validateEntity(entity, graph) {
58651             var result = {
58652               issues: [],
58653               provisional: false
58654             }; // runs validation and appends resulting issues
58655
58656             function runValidation(key) {
58657               var fn = _rules[key];
58658
58659               if (typeof fn !== 'function') {
58660                 console.error('no such validation rule = ' + key); // eslint-disable-line no-console
58661
58662                 return;
58663               }
58664
58665               var detected = fn(entity, graph).filter(applySeverityOverrides);
58666
58667               if (detected.provisional) {
58668                 // this validation should be run again later
58669                 result.provisional = true;
58670               }
58671
58672               result.issues = result.issues.concat(detected);
58673             } // run all rules
58674
58675
58676             Object.keys(_rules).forEach(runValidation);
58677             return result;
58678           } // If there are any override rules that match the issue type/subtype,
58679           // adjust severity (or disable it) and keep/discard as quickly as possible.
58680
58681
58682           function applySeverityOverrides(issue) {
58683             var type = issue.type;
58684             var subtype = issue.subtype || '';
58685             var i;
58686
58687             for (i = 0; i < _errorOverrides.length; i++) {
58688               if (_errorOverrides[i].type.test(type) && _errorOverrides[i].subtype.test(subtype)) {
58689                 issue.severity = 'error';
58690                 return true;
58691               }
58692             }
58693
58694             for (i = 0; i < _warningOverrides.length; i++) {
58695               if (_warningOverrides[i].type.test(type) && _warningOverrides[i].subtype.test(subtype)) {
58696                 issue.severity = 'warning';
58697                 return true;
58698               }
58699             }
58700
58701             for (i = 0; i < _disableOverrides.length; i++) {
58702               if (_disableOverrides[i].type.test(type) && _disableOverrides[i].subtype.test(subtype)) {
58703                 return false;
58704               }
58705             }
58706
58707             return true;
58708           } // `entityIDsToValidate()`   (private)
58709           // Collects the complete list of entityIDs related to the input entityIDs.
58710           //
58711           // Arguments
58712           //   `entityIDs` - Set or Array containing entityIDs.
58713           //   `graph` - graph containing the entities
58714           //
58715           // Returns
58716           //   Set containing entityIDs
58717           //
58718
58719
58720           function entityIDsToValidate(entityIDs, graph) {
58721             var seen = new Set();
58722             var collected = new Set();
58723             entityIDs.forEach(function (entityID) {
58724               // keep `seen` separate from `collected` because an `entityID`
58725               // could have been added to `collected` as a related entity through an earlier pass
58726               if (seen.has(entityID)) return;
58727               seen.add(entityID);
58728               var entity = graph.hasEntity(entityID);
58729               if (!entity) return;
58730               collected.add(entityID); // collect self
58731
58732               var checkParentRels = [entity];
58733
58734               if (entity.type === 'node') {
58735                 graph.parentWays(entity).forEach(function (parentWay) {
58736                   collected.add(parentWay.id); // collect parent ways
58737
58738                   checkParentRels.push(parentWay);
58739                 });
58740               } else if (entity.type === 'relation') {
58741                 entity.members.forEach(function (member) {
58742                   return collected.add(member.id);
58743                 }); // collect members
58744               } else if (entity.type === 'way') {
58745                 entity.nodes.forEach(function (nodeID) {
58746                   collected.add(nodeID); // collect child nodes
58747
58748                   graph._parentWays[nodeID].forEach(function (wayID) {
58749                     return collected.add(wayID);
58750                   }); // collect connected ways
58751
58752                 });
58753               }
58754
58755               checkParentRels.forEach(function (entity) {
58756                 // collect parent relations
58757                 if (entity.type !== 'relation') {
58758                   // but not super-relations
58759                   graph.parentRelations(entity).forEach(function (parentRelation) {
58760                     return collected.add(parentRelation.id);
58761                   });
58762                 }
58763               });
58764             });
58765             return collected;
58766           } // `updateResolvedIssues()`   (private)
58767           // Determine if any issues were resolved for the given entities.
58768           // This is called by `validate()` after validation of the head graph
58769           //
58770           // Arguments
58771           //   `entityIDs` - Set containing entity IDs.
58772           //
58773
58774
58775           function updateResolvedIssues(entityIDs) {
58776             entityIDs.forEach(function (entityID) {
58777               var headIssues = _headCache.issuesByEntityID[entityID];
58778               var baseIssues = _baseCache.issuesByEntityID[entityID];
58779               if (!baseIssues) return;
58780               baseIssues.forEach(function (issueID) {
58781                 if (headIssues && headIssues.has(issueID)) {
58782                   // issue still not resolved
58783                   _resolvedIssueIDs["delete"](issueID); // (did undo, or possibly fixed and then re-caused the issue)
58784
58785                 } else {
58786                   _resolvedIssueIDs.add(issueID);
58787                 }
58788               });
58789             });
58790           } // `validateEntitiesAsync()`   (private)
58791           // Schedule validation for many entities.
58792           //
58793           // Arguments
58794           //   `entityIDs` - Set containing entity IDs.
58795           //   `graph` - the graph to validate that contains those entities
58796           //   `cache` - the cache to store results in (_headCache or _baseCache)
58797           //
58798           // Returns
58799           //   A Promise fulfilled when the validation has completed.
58800           //   This may take time but happen in the background during browser idle time.
58801           //
58802
58803
58804           function validateEntitiesAsync(entityIDs, graph, cache) {
58805             // Enqueue the work
58806             var jobs = Array.from(entityIDs).map(function (entityID) {
58807               if (cache.queuedEntityIDs.has(entityID)) return null; // queued already
58808
58809               cache.queuedEntityIDs.add(entityID);
58810               return function () {
58811                 // clear caches for existing issues related to this entity
58812                 cache.uncacheEntityID(entityID);
58813                 cache.queuedEntityIDs["delete"](entityID); // detect new issues and update caches
58814
58815                 var entity = graph.hasEntity(entityID); // Sanity check: don't validate deleted entities
58816
58817                 if (entity) {
58818                   var result = validateEntity(entity, graph);
58819
58820                   if (result.provisional) {
58821                     // provisional result
58822                     cache.provisionalEntityIDs.add(entityID); // we'll need to revalidate this entity again later
58823                   }
58824
58825                   cache.cacheIssues(result.issues); // update cache
58826                 }
58827               };
58828             }).filter(Boolean); // Perform the work in chunks.
58829             // Because this will happen during idle callbacks, we want to choose a chunk size
58830             // that won't make the browser stutter too badly.
58831
58832             cache.queue = cache.queue.concat(utilArrayChunk(jobs, 100)); // Perform the work
58833
58834             if (cache.queuePromise) return cache.queuePromise;
58835             cache.queuePromise = processQueue(cache).then(function () {
58836               return revalidateProvisionalEntities(cache);
58837             })["catch"](function () {
58838               /* ignore */
58839             })["finally"](function () {
58840               return cache.queuePromise = null;
58841             });
58842             return cache.queuePromise;
58843           } // `revalidateProvisionalEntities()`   (private)
58844           // Sometimes a validator will return a "provisional" result.
58845           // In this situation, we'll need to revalidate the entity later.
58846           // This function waits a delay, then places them back into the validation queue.
58847           //
58848           // Arguments
58849           //   `cache` - The cache (_headCache or _baseCache)
58850           //
58851
58852
58853           function revalidateProvisionalEntities(cache) {
58854             if (!cache.provisionalEntityIDs.size) return; // nothing to do
58855
58856             var handle = window.setTimeout(function () {
58857               _deferredST["delete"](handle);
58858
58859               if (!cache.provisionalEntityIDs.size) return; // nothing to do
58860
58861               var graph = cache === _headCache ? _headGraph : context.history().base();
58862               validateEntitiesAsync(cache.provisionalEntityIDs, graph, cache);
58863             }, RETRY);
58864
58865             _deferredST.add(handle);
58866           } // `processQueue(queue)`   (private)
58867           // Process the next chunk of deferred validation work
58868           //
58869           // Arguments
58870           //   `cache` - The cache (_headCache or _baseCache)
58871           //
58872           // Returns
58873           //   A Promise fulfilled when the validation has completed.
58874           //   This may take time but happen in the background during browser idle time.
58875           //
58876
58877
58878           function processQueue(cache) {
58879             // const which = (cache === _headCache) ? 'head' : 'base';
58880             // console.log(`${which} queue length ${cache.queue.length}`);
58881             if (!cache.queue.length) return Promise.resolve(); // we're done
58882
58883             var chunk = cache.queue.pop();
58884             return new Promise(function (resolvePromise) {
58885               var handle = window.requestIdleCallback(function () {
58886                 _deferredRIC["delete"](handle); // const t0 = performance.now();
58887
58888
58889                 chunk.forEach(function (job) {
58890                   return job();
58891                 }); // const t1 = performance.now();
58892                 // console.log('chunk processed in ' + (t1 - t0) + ' ms');
58893
58894                 resolvePromise();
58895               });
58896
58897               _deferredRIC.add(handle);
58898             }).then(function () {
58899               // dispatch an event sometimes to redraw various UI things
58900               if (cache.queue.length % 25 === 0) dispatch.call('validated');
58901             }).then(function () {
58902               return processQueue(cache);
58903             });
58904           }
58905
58906           return validator;
58907         } // `validationCache()`   (private)
58908         // Creates a cache to store validation state
58909         // We create 2 of these:
58910         //   `_baseCache` for validation on the base graph (unedited)
58911         //   `_headCache` for validation on the head graph (user edits applied)
58912         //
58913
58914         function validationCache() {
58915           var cache = {
58916             queue: [],
58917             queuePromise: null,
58918             queuedEntityIDs: new Set(),
58919             provisionalEntityIDs: new Set(),
58920             issuesByIssueID: {},
58921             // issue.id -> issue
58922             issuesByEntityID: {} // entity.id -> set(issue.id)
58923
58924           };
58925
58926           cache.cacheIssues = function (issues) {
58927             issues.forEach(function (issue) {
58928               var entityIDs = issue.entityIds || [];
58929               entityIDs.forEach(function (entityID) {
58930                 if (!cache.issuesByEntityID[entityID]) {
58931                   cache.issuesByEntityID[entityID] = new Set();
58932                 }
58933
58934                 cache.issuesByEntityID[entityID].add(issue.id);
58935               });
58936               cache.issuesByIssueID[issue.id] = issue;
58937             });
58938           };
58939
58940           cache.uncacheIssue = function (issue) {
58941             // When multiple entities are involved (e.g. crossing_ways),
58942             // remove this issue from the other entity caches too..
58943             var entityIDs = issue.entityIds || [];
58944             entityIDs.forEach(function (entityID) {
58945               if (cache.issuesByEntityID[entityID]) {
58946                 cache.issuesByEntityID[entityID]["delete"](issue.id);
58947               }
58948             });
58949             delete cache.issuesByIssueID[issue.id];
58950           };
58951
58952           cache.uncacheIssues = function (issues) {
58953             issues.forEach(cache.uncacheIssue);
58954           };
58955
58956           cache.uncacheIssuesOfType = function (type) {
58957             var issuesOfType = Object.values(cache.issuesByIssueID).filter(function (issue) {
58958               return issue.type === type;
58959             });
58960             cache.uncacheIssues(issuesOfType);
58961           }; // Remove a single entity and all its related issues from the caches
58962
58963
58964           cache.uncacheEntityID = function (entityID) {
58965             var issueIDs = cache.issuesByEntityID[entityID];
58966
58967             if (issueIDs) {
58968               issueIDs.forEach(function (issueID) {
58969                 var issue = cache.issuesByIssueID[issueID];
58970
58971                 if (issue) {
58972                   cache.uncacheIssue(issue);
58973                 } else {
58974                   delete cache.issuesByIssueID[issueID];
58975                 }
58976               });
58977             }
58978
58979             delete cache.issuesByEntityID[entityID];
58980             cache.provisionalEntityIDs["delete"](entityID);
58981           };
58982
58983           return cache;
58984         }
58985
58986         function coreUploader(context) {
58987           var dispatch = dispatch$8( // Start and end events are dispatched exactly once each per legitimate outside call to `save`
58988           'saveStarted', // dispatched as soon as a call to `save` has been deemed legitimate
58989           'saveEnded', // dispatched after the result event has been dispatched
58990           'willAttemptUpload', // dispatched before the actual upload call occurs, if it will
58991           'progressChanged', // Each save results in one of these outcomes:
58992           'resultNoChanges', // upload wasn't attempted since there were no edits
58993           'resultErrors', // upload failed due to errors
58994           'resultConflicts', // upload failed due to data conflicts
58995           'resultSuccess' // upload completed without errors
58996           );
58997           var _isSaving = false;
58998           var _conflicts = [];
58999           var _errors = [];
59000
59001           var _origChanges;
59002
59003           var _discardTags = {};
59004           _mainFileFetcher.get('discarded').then(function (d) {
59005             _discardTags = d;
59006           })["catch"](function () {
59007             /* ignore */
59008           });
59009           var uploader = utilRebind({}, dispatch, 'on');
59010
59011           uploader.isSaving = function () {
59012             return _isSaving;
59013           };
59014
59015           uploader.save = function (changeset, tryAgain, checkConflicts) {
59016             // Guard against accidentally entering save code twice - #4641
59017             if (_isSaving && !tryAgain) {
59018               return;
59019             }
59020
59021             var osm = context.connection();
59022             if (!osm) return; // If user somehow got logged out mid-save, try to reauthenticate..
59023             // This can happen if they were logged in from before, but the tokens are no longer valid.
59024
59025             if (!osm.authenticated()) {
59026               osm.authenticate(function (err) {
59027                 if (!err) {
59028                   uploader.save(changeset, tryAgain, checkConflicts); // continue where we left off..
59029                 }
59030               });
59031               return;
59032             }
59033
59034             if (!_isSaving) {
59035               _isSaving = true;
59036               dispatch.call('saveStarted', this);
59037             }
59038
59039             var history = context.history();
59040             _conflicts = [];
59041             _errors = []; // Store original changes, in case user wants to download them as an .osc file
59042
59043             _origChanges = history.changes(actionDiscardTags(history.difference(), _discardTags)); // First time, `history.perform` a no-op action.
59044             // Any conflict resolutions will be done as `history.replace`
59045             // Remember to pop this later if needed
59046
59047             if (!tryAgain) {
59048               history.perform(actionNoop());
59049             } // Attempt a fast upload.. If there are conflicts, re-enter with `checkConflicts = true`
59050
59051
59052             if (!checkConflicts) {
59053               upload(changeset); // Do the full (slow) conflict check..
59054             } else {
59055               performFullConflictCheck(changeset);
59056             }
59057           };
59058
59059           function performFullConflictCheck(changeset) {
59060             var osm = context.connection();
59061             if (!osm) return;
59062             var history = context.history();
59063             var localGraph = context.graph();
59064             var remoteGraph = coreGraph(history.base(), true);
59065             var summary = history.difference().summary();
59066             var _toCheck = [];
59067
59068             for (var i = 0; i < summary.length; i++) {
59069               var item = summary[i];
59070
59071               if (item.changeType === 'modified') {
59072                 _toCheck.push(item.entity.id);
59073               }
59074             }
59075
59076             var _toLoad = withChildNodes(_toCheck, localGraph);
59077
59078             var _loaded = {};
59079             var _toLoadCount = 0;
59080             var _toLoadTotal = _toLoad.length;
59081
59082             if (_toCheck.length) {
59083               dispatch.call('progressChanged', this, _toLoadCount, _toLoadTotal);
59084
59085               _toLoad.forEach(function (id) {
59086                 _loaded[id] = false;
59087               });
59088
59089               osm.loadMultiple(_toLoad, loaded);
59090             } else {
59091               upload(changeset);
59092             }
59093
59094             return;
59095
59096             function withChildNodes(ids, graph) {
59097               var s = new Set(ids);
59098               ids.forEach(function (id) {
59099                 var entity = graph.entity(id);
59100                 if (entity.type !== 'way') return;
59101                 graph.childNodes(entity).forEach(function (child) {
59102                   if (child.version !== undefined) {
59103                     s.add(child.id);
59104                   }
59105                 });
59106               });
59107               return Array.from(s);
59108             } // Reload modified entities into an alternate graph and check for conflicts..
59109
59110
59111             function loaded(err, result) {
59112               if (_errors.length) return;
59113
59114               if (err) {
59115                 _errors.push({
59116                   msg: err.message || err.responseText,
59117                   details: [_t('save.status_code', {
59118                     code: err.status
59119                   })]
59120                 });
59121
59122                 didResultInErrors();
59123               } else {
59124                 var loadMore = [];
59125                 result.data.forEach(function (entity) {
59126                   remoteGraph.replace(entity);
59127                   _loaded[entity.id] = true;
59128                   _toLoad = _toLoad.filter(function (val) {
59129                     return val !== entity.id;
59130                   });
59131                   if (!entity.visible) return; // Because loadMultiple doesn't download /full like loadEntity,
59132                   // need to also load children that aren't already being checked..
59133
59134                   var i, id;
59135
59136                   if (entity.type === 'way') {
59137                     for (i = 0; i < entity.nodes.length; i++) {
59138                       id = entity.nodes[i];
59139
59140                       if (_loaded[id] === undefined) {
59141                         _loaded[id] = false;
59142                         loadMore.push(id);
59143                       }
59144                     }
59145                   } else if (entity.type === 'relation' && entity.isMultipolygon()) {
59146                     for (i = 0; i < entity.members.length; i++) {
59147                       id = entity.members[i].id;
59148
59149                       if (_loaded[id] === undefined) {
59150                         _loaded[id] = false;
59151                         loadMore.push(id);
59152                       }
59153                     }
59154                   }
59155                 });
59156                 _toLoadCount += result.data.length;
59157                 _toLoadTotal += loadMore.length;
59158                 dispatch.call('progressChanged', this, _toLoadCount, _toLoadTotal);
59159
59160                 if (loadMore.length) {
59161                   _toLoad.push.apply(_toLoad, loadMore);
59162
59163                   osm.loadMultiple(loadMore, loaded);
59164                 }
59165
59166                 if (!_toLoad.length) {
59167                   detectConflicts();
59168                   upload(changeset);
59169                 }
59170               }
59171             }
59172
59173             function detectConflicts() {
59174               function choice(id, text, _action) {
59175                 return {
59176                   id: id,
59177                   text: text,
59178                   action: function action() {
59179                     history.replace(_action);
59180                   }
59181                 };
59182               }
59183
59184               function formatUser(d) {
59185                 return '<a href="' + osm.userURL(d) + '" target="_blank">' + d + '</a>';
59186               }
59187
59188               function entityName(entity) {
59189                 return utilDisplayName(entity) || utilDisplayType(entity.id) + ' ' + entity.id;
59190               }
59191
59192               function sameVersions(local, remote) {
59193                 if (local.version !== remote.version) return false;
59194
59195                 if (local.type === 'way') {
59196                   var children = utilArrayUnion(local.nodes, remote.nodes);
59197
59198                   for (var i = 0; i < children.length; i++) {
59199                     var a = localGraph.hasEntity(children[i]);
59200                     var b = remoteGraph.hasEntity(children[i]);
59201                     if (a && b && a.version !== b.version) return false;
59202                   }
59203                 }
59204
59205                 return true;
59206               }
59207
59208               _toCheck.forEach(function (id) {
59209                 var local = localGraph.entity(id);
59210                 var remote = remoteGraph.entity(id);
59211                 if (sameVersions(local, remote)) return;
59212                 var merge = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags, formatUser);
59213                 history.replace(merge);
59214                 var mergeConflicts = merge.conflicts();
59215                 if (!mergeConflicts.length) return; // merged safely
59216
59217                 var forceLocal = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_local');
59218                 var forceRemote = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_remote');
59219                 var keepMine = _t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore'));
59220                 var keepTheirs = _t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
59221
59222                 _conflicts.push({
59223                   id: id,
59224                   name: entityName(local),
59225                   details: mergeConflicts,
59226                   chosen: 1,
59227                   choices: [choice(id, keepMine, forceLocal), choice(id, keepTheirs, forceRemote)]
59228                 });
59229               });
59230             }
59231           }
59232
59233           function upload(changeset) {
59234             var osm = context.connection();
59235
59236             if (!osm) {
59237               _errors.push({
59238                 msg: 'No OSM Service'
59239               });
59240             }
59241
59242             if (_conflicts.length) {
59243               didResultInConflicts(changeset);
59244             } else if (_errors.length) {
59245               didResultInErrors();
59246             } else {
59247               var history = context.history();
59248               var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
59249
59250               if (changes.modified.length || changes.created.length || changes.deleted.length) {
59251                 dispatch.call('willAttemptUpload', this);
59252                 osm.putChangeset(changeset, changes, uploadCallback);
59253               } else {
59254                 // changes were insignificant or reverted by user
59255                 didResultInNoChanges();
59256               }
59257             }
59258           }
59259
59260           function uploadCallback(err, changeset) {
59261             if (err) {
59262               if (err.status === 409) {
59263                 // 409 Conflict
59264                 uploader.save(changeset, true, true); // tryAgain = true, checkConflicts = true
59265               } else {
59266                 _errors.push({
59267                   msg: err.message || err.responseText,
59268                   details: [_t('save.status_code', {
59269                     code: err.status
59270                   })]
59271                 });
59272
59273                 didResultInErrors();
59274               }
59275             } else {
59276               didResultInSuccess(changeset);
59277             }
59278           }
59279
59280           function didResultInNoChanges() {
59281             dispatch.call('resultNoChanges', this);
59282             endSave();
59283             context.flush(); // reset iD
59284           }
59285
59286           function didResultInErrors() {
59287             context.history().pop();
59288             dispatch.call('resultErrors', this, _errors);
59289             endSave();
59290           }
59291
59292           function didResultInConflicts(changeset) {
59293             _conflicts.sort(function (a, b) {
59294               return b.id.localeCompare(a.id);
59295             });
59296
59297             dispatch.call('resultConflicts', this, changeset, _conflicts, _origChanges);
59298             endSave();
59299           }
59300
59301           function didResultInSuccess(changeset) {
59302             // delete the edit stack cached to local storage
59303             context.history().clearSaved();
59304             dispatch.call('resultSuccess', this, changeset); // Add delay to allow for postgres replication #1646 #2678
59305
59306             window.setTimeout(function () {
59307               endSave();
59308               context.flush(); // reset iD
59309             }, 2500);
59310           }
59311
59312           function endSave() {
59313             _isSaving = false;
59314             dispatch.call('saveEnded', this);
59315           }
59316
59317           uploader.cancelConflictResolution = function () {
59318             context.history().pop();
59319           };
59320
59321           uploader.processResolvedConflicts = function (changeset) {
59322             var history = context.history();
59323
59324             for (var i = 0; i < _conflicts.length; i++) {
59325               if (_conflicts[i].chosen === 1) {
59326                 // user chose "use theirs"
59327                 var entity = context.hasEntity(_conflicts[i].id);
59328
59329                 if (entity && entity.type === 'way') {
59330                   var children = utilArrayUniq(entity.nodes);
59331
59332                   for (var j = 0; j < children.length; j++) {
59333                     history.replace(actionRevert(children[j]));
59334                   }
59335                 }
59336
59337                 history.replace(actionRevert(_conflicts[i].id));
59338               }
59339             }
59340
59341             uploader.save(changeset, true, false); // tryAgain = true, checkConflicts = false
59342           };
59343
59344           uploader.reset = function () {};
59345
59346           return uploader;
59347         }
59348
59349         var abs = Math.abs;
59350         var exp = Math.exp;
59351         var E = Math.E;
59352
59353         var FORCED = fails(function () {
59354           // eslint-disable-next-line es/no-math-sinh -- required for testing
59355           return Math.sinh(-2e-17) != -2e-17;
59356         });
59357
59358         // `Math.sinh` method
59359         // https://tc39.es/ecma262/#sec-math.sinh
59360         // V8 near Chromium 38 has a problem with very small numbers
59361         _export({ target: 'Math', stat: true, forced: FORCED }, {
59362           sinh: function sinh(x) {
59363             return abs(x = +x) < 1 ? (mathExpm1(x) - mathExpm1(-x)) / 2 : (exp(x - 1) - exp(-x - 1)) * (E / 2);
59364           }
59365         });
59366
59367         var isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2; // listen for DPI change, e.g. when dragging a browser window from a retina to non-retina screen
59368
59369         window.matchMedia("\n        (-webkit-min-device-pixel-ratio: 2), /* Safari */\n        (min-resolution: 2dppx),             /* standard */\n        (min-resolution: 192dpi)             /* fallback */\n    ").addListener(function () {
59370           isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
59371         });
59372
59373         function localeDateString(s) {
59374           if (!s) return null;
59375           var options = {
59376             day: 'numeric',
59377             month: 'short',
59378             year: 'numeric'
59379           };
59380           var d = new Date(s);
59381           if (isNaN(d.getTime())) return null;
59382           return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
59383         }
59384
59385         function vintageRange(vintage) {
59386           var s;
59387
59388           if (vintage.start || vintage.end) {
59389             s = vintage.start || '?';
59390
59391             if (vintage.start !== vintage.end) {
59392               s += ' - ' + (vintage.end || '?');
59393             }
59394           }
59395
59396           return s;
59397         }
59398
59399         function rendererBackgroundSource(data) {
59400           var source = Object.assign({}, data); // shallow copy
59401
59402           var _offset = [0, 0];
59403           var _name = source.name;
59404           var _description = source.description;
59405
59406           var _best = !!source.best;
59407
59408           var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
59409
59410           source.tileSize = data.tileSize || 256;
59411           source.zoomExtent = data.zoomExtent || [0, 22];
59412           source.overzoom = data.overzoom !== false;
59413
59414           source.offset = function (val) {
59415             if (!arguments.length) return _offset;
59416             _offset = val;
59417             return source;
59418           };
59419
59420           source.nudge = function (val, zoomlevel) {
59421             _offset[0] += val[0] / Math.pow(2, zoomlevel);
59422             _offset[1] += val[1] / Math.pow(2, zoomlevel);
59423             return source;
59424           };
59425
59426           source.name = function () {
59427             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
59428             return _t('imagery.' + id_safe + '.name', {
59429               "default": _name
59430             });
59431           };
59432
59433           source.label = function () {
59434             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
59435             return _t.html('imagery.' + id_safe + '.name', {
59436               "default": _name
59437             });
59438           };
59439
59440           source.description = function () {
59441             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
59442             return _t.html('imagery.' + id_safe + '.description', {
59443               "default": _description
59444             });
59445           };
59446
59447           source.best = function () {
59448             return _best;
59449           };
59450
59451           source.area = function () {
59452             if (!data.polygon) return Number.MAX_VALUE; // worldwide
59453
59454             var area = d3_geoArea({
59455               type: 'MultiPolygon',
59456               coordinates: [data.polygon]
59457             });
59458             return isNaN(area) ? 0 : area;
59459           };
59460
59461           source.imageryUsed = function () {
59462             return _name || source.id;
59463           };
59464
59465           source.template = function (val) {
59466             if (!arguments.length) return _template;
59467
59468             if (source.id === 'custom' || source.id === 'Bing') {
59469               _template = val;
59470             }
59471
59472             return source;
59473           };
59474
59475           source.url = function (coord) {
59476             var result = _template;
59477             if (result === '') return result; // source 'none'
59478             // Guess a type based on the tokens present in the template
59479             // (This is for 'custom' source, where we don't know)
59480
59481             if (!source.type) {
59482               if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(_template)) {
59483                 source.type = 'wms';
59484                 source.projection = 'EPSG:3857'; // guess
59485               } else if (/\{(x|y)\}/.test(_template)) {
59486                 source.type = 'tms';
59487               } else if (/\{u\}/.test(_template)) {
59488                 source.type = 'bing';
59489               }
59490             }
59491
59492             if (source.type === 'wms') {
59493               var tileToProjectedCoords = function tileToProjectedCoords(x, y, z) {
59494                 //polyfill for IE11, PhantomJS
59495                 var sinh = Math.sinh || function (x) {
59496                   var y = Math.exp(x);
59497                   return (y - 1 / y) / 2;
59498                 };
59499
59500                 var zoomSize = Math.pow(2, z);
59501                 var lon = x / zoomSize * Math.PI * 2 - Math.PI;
59502                 var lat = Math.atan(sinh(Math.PI * (1 - 2 * y / zoomSize)));
59503
59504                 switch (source.projection) {
59505                   case 'EPSG:4326':
59506                     return {
59507                       x: lon * 180 / Math.PI,
59508                       y: lat * 180 / Math.PI
59509                     };
59510
59511                   default:
59512                     // EPSG:3857 and synonyms
59513                     var mercCoords = mercatorRaw(lon, lat);
59514                     return {
59515                       x: 20037508.34 / Math.PI * mercCoords[0],
59516                       y: 20037508.34 / Math.PI * mercCoords[1]
59517                     };
59518                 }
59519               };
59520
59521               var tileSize = source.tileSize;
59522               var projection = source.projection;
59523               var minXmaxY = tileToProjectedCoords(coord[0], coord[1], coord[2]);
59524               var maxXminY = tileToProjectedCoords(coord[0] + 1, coord[1] + 1, coord[2]);
59525               result = result.replace(/\{(\w+)\}/g, function (token, key) {
59526                 switch (key) {
59527                   case 'width':
59528                   case 'height':
59529                     return tileSize;
59530
59531                   case 'proj':
59532                     return projection;
59533
59534                   case 'wkid':
59535                     return projection.replace(/^EPSG:/, '');
59536
59537                   case 'bbox':
59538                     // WMS 1.3 flips x/y for some coordinate systems including EPSG:4326 - #7557
59539                     if (projection === 'EPSG:4326' && // The CRS parameter implies version 1.3 (prior versions use SRS)
59540                     /VERSION=1.3|CRS={proj}/.test(source.template().toUpperCase())) {
59541                       return maxXminY.y + ',' + minXmaxY.x + ',' + minXmaxY.y + ',' + maxXminY.x;
59542                     } else {
59543                       return minXmaxY.x + ',' + maxXminY.y + ',' + maxXminY.x + ',' + minXmaxY.y;
59544                     }
59545
59546                   case 'w':
59547                     return minXmaxY.x;
59548
59549                   case 's':
59550                     return maxXminY.y;
59551
59552                   case 'n':
59553                     return maxXminY.x;
59554
59555                   case 'e':
59556                     return minXmaxY.y;
59557
59558                   default:
59559                     return token;
59560                 }
59561               });
59562             } else if (source.type === 'tms') {
59563               result = result.replace('{x}', coord[0]).replace('{y}', coord[1]) // TMS-flipped y coordinate
59564               .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1).replace(/\{z(oom)?\}/, coord[2]) // only fetch retina tiles for retina screens
59565               .replace(/\{@2x\}|\{r\}/, isRetina ? '@2x' : '');
59566             } else if (source.type === 'bing') {
59567               result = result.replace('{u}', function () {
59568                 var u = '';
59569
59570                 for (var zoom = coord[2]; zoom > 0; zoom--) {
59571                   var b = 0;
59572                   var mask = 1 << zoom - 1;
59573                   if ((coord[0] & mask) !== 0) b++;
59574                   if ((coord[1] & mask) !== 0) b += 2;
59575                   u += b.toString();
59576                 }
59577
59578                 return u;
59579               });
59580             } // these apply to any type..
59581
59582
59583             result = result.replace(/\{switch:([^}]+)\}/, function (s, r) {
59584               var subdomains = r.split(',');
59585               return subdomains[(coord[0] + coord[1]) % subdomains.length];
59586             });
59587             return result;
59588           };
59589
59590           source.validZoom = function (z) {
59591             return source.zoomExtent[0] <= z && (source.overzoom || source.zoomExtent[1] > z);
59592           };
59593
59594           source.isLocatorOverlay = function () {
59595             return source.id === 'mapbox_locator_overlay';
59596           };
59597           /* hides a source from the list, but leaves it available for use */
59598
59599
59600           source.isHidden = function () {
59601             return source.id === 'DigitalGlobe-Premium-vintage' || source.id === 'DigitalGlobe-Standard-vintage';
59602           };
59603
59604           source.copyrightNotices = function () {};
59605
59606           source.getMetadata = function (center, tileCoord, callback) {
59607             var vintage = {
59608               start: localeDateString(source.startDate),
59609               end: localeDateString(source.endDate)
59610             };
59611             vintage.range = vintageRange(vintage);
59612             var metadata = {
59613               vintage: vintage
59614             };
59615             callback(null, metadata);
59616           };
59617
59618           return source;
59619         }
59620
59621         rendererBackgroundSource.Bing = function (data, dispatch) {
59622           // https://docs.microsoft.com/en-us/bingmaps/rest-services/imagery/get-imagery-metadata
59623           // https://docs.microsoft.com/en-us/bingmaps/rest-services/directly-accessing-the-bing-maps-tiles
59624           //fallback url template
59625           data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=10555&n=z';
59626           var bing = rendererBackgroundSource(data); //var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // P2, JOSM, etc
59627
59628           var key = 'Ak5oTE46TUbjRp08OFVcGpkARErDobfpuyNKa-W2mQ8wbt1K1KL8p1bIRwWwcF-Q'; // iD
59629
59630           /*
59631           missing tile image strictness param (n=)
59632           •   n=f -> (Fail) returns a 404
59633           •   n=z -> (Empty) returns a 200 with 0 bytes (no content)
59634           •   n=t -> (Transparent) returns a 200 with a transparent (png) tile
59635           */
59636
59637           var strictParam = 'n';
59638           var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&uriScheme=https&key=' + key;
59639           var cache = {};
59640           var inflight = {};
59641           var providers = [];
59642           d3_json(url).then(function (json) {
59643             var imageryResource = json.resourceSets[0].resources[0]; //retrieve and prepare up to date imagery template
59644
59645             var template = imageryResource.imageUrl; //https://ecn.{subdomain}.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=10339
59646
59647             var subDomains = imageryResource.imageUrlSubdomains; //["t0, t1, t2, t3"]
59648
59649             var subDomainNumbers = subDomains.map(function (subDomain) {
59650               return subDomain.substring(1);
59651             }).join(',');
59652             template = template.replace('{subdomain}', "t{switch:".concat(subDomainNumbers, "}")).replace('{quadkey}', '{u}');
59653
59654             if (!new URLSearchParams(template).has(strictParam)) {
59655               template += "&".concat(strictParam, "=z");
59656             }
59657
59658             bing.template(template);
59659             providers = imageryResource.imageryProviders.map(function (provider) {
59660               return {
59661                 attribution: provider.attribution,
59662                 areas: provider.coverageAreas.map(function (area) {
59663                   return {
59664                     zoom: [area.zoomMin, area.zoomMax],
59665                     extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
59666                   };
59667                 })
59668               };
59669             });
59670             dispatch.call('change');
59671           })["catch"](function () {
59672             /* ignore */
59673           });
59674
59675           bing.copyrightNotices = function (zoom, extent) {
59676             zoom = Math.min(zoom, 21);
59677             return providers.filter(function (provider) {
59678               return provider.areas.some(function (area) {
59679                 return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
59680               });
59681             }).map(function (provider) {
59682               return provider.attribution;
59683             }).join(', ');
59684           };
59685
59686           bing.getMetadata = function (center, tileCoord, callback) {
59687             var tileID = tileCoord.slice(0, 3).join('/');
59688             var zoom = Math.min(tileCoord[2], 21);
59689             var centerPoint = center[1] + ',' + center[0]; // lat,lng
59690
59691             var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint + '?zl=' + zoom + '&key=' + key;
59692             if (inflight[tileID]) return;
59693
59694             if (!cache[tileID]) {
59695               cache[tileID] = {};
59696             }
59697
59698             if (cache[tileID] && cache[tileID].metadata) {
59699               return callback(null, cache[tileID].metadata);
59700             }
59701
59702             inflight[tileID] = true;
59703             d3_json(url).then(function (result) {
59704               delete inflight[tileID];
59705
59706               if (!result) {
59707                 throw new Error('Unknown Error');
59708               }
59709
59710               var vintage = {
59711                 start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
59712                 end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
59713               };
59714               vintage.range = vintageRange(vintage);
59715               var metadata = {
59716                 vintage: vintage
59717               };
59718               cache[tileID].metadata = metadata;
59719               if (callback) callback(null, metadata);
59720             })["catch"](function (err) {
59721               delete inflight[tileID];
59722               if (callback) callback(err.message);
59723             });
59724           };
59725
59726           bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
59727           return bing;
59728         };
59729
59730         rendererBackgroundSource.Esri = function (data) {
59731           // in addition to using the tilemap at zoom level 20, overzoom real tiles - #4327 (deprecated technique, but it works)
59732           if (data.template.match(/blankTile/) === null) {
59733             data.template = data.template + '?blankTile=false';
59734           }
59735
59736           var esri = rendererBackgroundSource(data);
59737           var cache = {};
59738           var inflight = {};
59739
59740           var _prevCenter; // use a tilemap service to set maximum zoom for esri tiles dynamically
59741           // https://developers.arcgis.com/documentation/tiled-elevation-service/
59742
59743
59744           esri.fetchTilemap = function (center) {
59745             // skip if we have already fetched a tilemap within 5km
59746             if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5000) return;
59747             _prevCenter = center; // tiles are available globally to zoom level 19, afterward they may or may not be present
59748
59749             var z = 20; // first generate a random url using the template
59750
59751             var dummyUrl = esri.url([1, 2, 3]); // calculate url z/y/x from the lat/long of the center of the map
59752
59753             var x = Math.floor((center[0] + 180) / 360 * Math.pow(2, z));
59754             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)); // fetch an 8x8 grid to leverage cache
59755
59756             var tilemapUrl = dummyUrl.replace(/tile\/[0-9]+\/[0-9]+\/[0-9]+\?blankTile=false/, 'tilemap') + '/' + z + '/' + y + '/' + x + '/8/8'; // make the request and introspect the response from the tilemap server
59757
59758             d3_json(tilemapUrl).then(function (tilemap) {
59759               if (!tilemap) {
59760                 throw new Error('Unknown Error');
59761               }
59762
59763               var hasTiles = true;
59764
59765               for (var i = 0; i < tilemap.data.length; i++) {
59766                 // 0 means an individual tile in the grid doesn't exist
59767                 if (!tilemap.data[i]) {
59768                   hasTiles = false;
59769                   break;
59770                 }
59771               } // if any tiles are missing at level 20 we restrict maxZoom to 19
59772
59773
59774               esri.zoomExtent[1] = hasTiles ? 22 : 19;
59775             })["catch"](function () {
59776               /* ignore */
59777             });
59778           };
59779
59780           esri.getMetadata = function (center, tileCoord, callback) {
59781             var tileID = tileCoord.slice(0, 3).join('/');
59782             var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
59783             var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
59784
59785             var unknown = _t('info_panels.background.unknown');
59786             var metadataLayer;
59787             var vintage = {};
59788             var metadata = {};
59789             if (inflight[tileID]) return;
59790
59791             switch (true) {
59792               case zoom >= 20 && esri.id === 'EsriWorldImageryClarity':
59793                 metadataLayer = 4;
59794                 break;
59795
59796               case zoom >= 19:
59797                 metadataLayer = 3;
59798                 break;
59799
59800               case zoom >= 17:
59801                 metadataLayer = 2;
59802                 break;
59803
59804               case zoom >= 13:
59805                 metadataLayer = 0;
59806                 break;
59807
59808               default:
59809                 metadataLayer = 99;
59810             }
59811
59812             var url; // build up query using the layer appropriate to the current zoom
59813
59814             if (esri.id === 'EsriWorldImagery') {
59815               url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/';
59816             } else if (esri.id === 'EsriWorldImageryClarity') {
59817               url = 'https://serviceslab.arcgisonline.com/arcgis/rest/services/Clarity_World_Imagery/MapServer/';
59818             }
59819
59820             url += metadataLayer + '/query?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
59821
59822             if (!cache[tileID]) {
59823               cache[tileID] = {};
59824             }
59825
59826             if (cache[tileID] && cache[tileID].metadata) {
59827               return callback(null, cache[tileID].metadata);
59828             } // accurate metadata is only available >= 13
59829
59830
59831             if (metadataLayer === 99) {
59832               vintage = {
59833                 start: null,
59834                 end: null,
59835                 range: null
59836               };
59837               metadata = {
59838                 vintage: null,
59839                 source: unknown,
59840                 description: unknown,
59841                 resolution: unknown,
59842                 accuracy: unknown
59843               };
59844               callback(null, metadata);
59845             } else {
59846               inflight[tileID] = true;
59847               d3_json(url).then(function (result) {
59848                 delete inflight[tileID];
59849
59850                 if (!result) {
59851                   throw new Error('Unknown Error');
59852                 } else if (result.features && result.features.length < 1) {
59853                   throw new Error('No Results');
59854                 } else if (result.error && result.error.message) {
59855                   throw new Error(result.error.message);
59856                 } // pass through the discrete capture date from metadata
59857
59858
59859                 var captureDate = localeDateString(result.features[0].attributes.SRC_DATE2);
59860                 vintage = {
59861                   start: captureDate,
59862                   end: captureDate,
59863                   range: captureDate
59864                 };
59865                 metadata = {
59866                   vintage: vintage,
59867                   source: clean(result.features[0].attributes.NICE_NAME),
59868                   description: clean(result.features[0].attributes.NICE_DESC),
59869                   resolution: clean(+parseFloat(result.features[0].attributes.SRC_RES).toFixed(4)),
59870                   accuracy: clean(+parseFloat(result.features[0].attributes.SRC_ACC).toFixed(4))
59871                 }; // append units - meters
59872
59873                 if (isFinite(metadata.resolution)) {
59874                   metadata.resolution += ' m';
59875                 }
59876
59877                 if (isFinite(metadata.accuracy)) {
59878                   metadata.accuracy += ' m';
59879                 }
59880
59881                 cache[tileID].metadata = metadata;
59882                 if (callback) callback(null, metadata);
59883               })["catch"](function (err) {
59884                 delete inflight[tileID];
59885                 if (callback) callback(err.message);
59886               });
59887             }
59888
59889             function clean(val) {
59890               return String(val).trim() || unknown;
59891             }
59892           };
59893
59894           return esri;
59895         };
59896
59897         rendererBackgroundSource.None = function () {
59898           var source = rendererBackgroundSource({
59899             id: 'none',
59900             template: ''
59901           });
59902
59903           source.name = function () {
59904             return _t('background.none');
59905           };
59906
59907           source.label = function () {
59908             return _t.html('background.none');
59909           };
59910
59911           source.imageryUsed = function () {
59912             return null;
59913           };
59914
59915           source.area = function () {
59916             return -1; // sources in background pane are sorted by area
59917           };
59918
59919           return source;
59920         };
59921
59922         rendererBackgroundSource.Custom = function (template) {
59923           var source = rendererBackgroundSource({
59924             id: 'custom',
59925             template: template
59926           });
59927
59928           source.name = function () {
59929             return _t('background.custom');
59930           };
59931
59932           source.label = function () {
59933             return _t.html('background.custom');
59934           };
59935
59936           source.imageryUsed = function () {
59937             // sanitize personal connection tokens - #6801
59938             var cleaned = source.template(); // from query string parameters
59939
59940             if (cleaned.indexOf('?') !== -1) {
59941               var parts = cleaned.split('?', 2);
59942               var qs = utilStringQs(parts[1]);
59943               ['access_token', 'connectId', 'token'].forEach(function (param) {
59944                 if (qs[param]) {
59945                   qs[param] = '{apikey}';
59946                 }
59947               });
59948               cleaned = parts[0] + '?' + utilQsString(qs, true); // true = soft encode
59949             } // from wms/wmts api path parameters
59950
59951
59952             cleaned = cleaned.replace(/token\/(\w+)/, 'token/{apikey}');
59953             return 'Custom (' + cleaned + ' )';
59954           };
59955
59956           source.area = function () {
59957             return -2; // sources in background pane are sorted by area
59958           };
59959
59960           return source;
59961         };
59962
59963         function rendererTileLayer(context) {
59964           var transformProp = utilPrefixCSSProperty('Transform');
59965           var tiler = utilTiler();
59966           var _tileSize = 256;
59967
59968           var _projection;
59969
59970           var _cache = {};
59971
59972           var _tileOrigin;
59973
59974           var _zoom;
59975
59976           var _source;
59977
59978           function tileSizeAtZoom(d, z) {
59979             var EPSILON = 0.002; // close seams
59980
59981             return _tileSize * Math.pow(2, z - d[2]) / _tileSize + EPSILON;
59982           }
59983
59984           function atZoom(t, distance) {
59985             var power = Math.pow(2, distance);
59986             return [Math.floor(t[0] * power), Math.floor(t[1] * power), t[2] + distance];
59987           }
59988
59989           function lookUp(d) {
59990             for (var up = -1; up > -d[2]; up--) {
59991               var tile = atZoom(d, up);
59992
59993               if (_cache[_source.url(tile)] !== false) {
59994                 return tile;
59995               }
59996             }
59997           }
59998
59999           function uniqueBy(a, n) {
60000             var o = [];
60001             var seen = {};
60002
60003             for (var i = 0; i < a.length; i++) {
60004               if (seen[a[i][n]] === undefined) {
60005                 o.push(a[i]);
60006                 seen[a[i][n]] = true;
60007               }
60008             }
60009
60010             return o;
60011           }
60012
60013           function addSource(d) {
60014             d.push(_source.url(d));
60015             return d;
60016           } // Update tiles based on current state of `projection`.
60017
60018
60019           function background(selection) {
60020             _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
60021             var pixelOffset;
60022
60023             if (_source) {
60024               pixelOffset = [_source.offset()[0] * Math.pow(2, _zoom), _source.offset()[1] * Math.pow(2, _zoom)];
60025             } else {
60026               pixelOffset = [0, 0];
60027             }
60028
60029             var translate = [_projection.translate()[0] + pixelOffset[0], _projection.translate()[1] + pixelOffset[1]];
60030             tiler.scale(_projection.scale() * 2 * Math.PI).translate(translate);
60031             _tileOrigin = [_projection.scale() * Math.PI - translate[0], _projection.scale() * Math.PI - translate[1]];
60032             render(selection);
60033           } // Derive the tiles onscreen, remove those offscreen and position them.
60034           // Important that this part not depend on `_projection` because it's
60035           // rentered when tiles load/error (see #644).
60036
60037
60038           function render(selection) {
60039             if (!_source) return;
60040             var requests = [];
60041             var showDebug = context.getDebug('tile') && !_source.overlay;
60042
60043             if (_source.validZoom(_zoom)) {
60044               tiler.skipNullIsland(!!_source.overlay);
60045               tiler().forEach(function (d) {
60046                 addSource(d);
60047                 if (d[3] === '') return;
60048                 if (typeof d[3] !== 'string') return; // Workaround for #2295
60049
60050                 requests.push(d);
60051
60052                 if (_cache[d[3]] === false && lookUp(d)) {
60053                   requests.push(addSource(lookUp(d)));
60054                 }
60055               });
60056               requests = uniqueBy(requests, 3).filter(function (r) {
60057                 // don't re-request tiles which have failed in the past
60058                 return _cache[r[3]] !== false;
60059               });
60060             }
60061
60062             function load(d3_event, d) {
60063               _cache[d[3]] = true;
60064               select(this).on('error', null).on('load', null).classed('tile-loaded', true);
60065               render(selection);
60066             }
60067
60068             function error(d3_event, d) {
60069               _cache[d[3]] = false;
60070               select(this).on('error', null).on('load', null).remove();
60071               render(selection);
60072             }
60073
60074             function imageTransform(d) {
60075               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
60076
60077               var scale = tileSizeAtZoom(d, _zoom);
60078               return 'translate(' + (d[0] * ts - _tileOrigin[0]) + 'px,' + (d[1] * ts - _tileOrigin[1]) + 'px) ' + 'scale(' + scale + ',' + scale + ')';
60079             }
60080
60081             function tileCenter(d) {
60082               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
60083
60084               return [d[0] * ts - _tileOrigin[0] + ts / 2, d[1] * ts - _tileOrigin[1] + ts / 2];
60085             }
60086
60087             function debugTransform(d) {
60088               var coord = tileCenter(d);
60089               return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
60090             } // Pick a representative tile near the center of the viewport
60091             // (This is useful for sampling the imagery vintage)
60092
60093
60094             var dims = tiler.size();
60095             var mapCenter = [dims[0] / 2, dims[1] / 2];
60096             var minDist = Math.max(dims[0], dims[1]);
60097             var nearCenter;
60098             requests.forEach(function (d) {
60099               var c = tileCenter(d);
60100               var dist = geoVecLength(c, mapCenter);
60101
60102               if (dist < minDist) {
60103                 minDist = dist;
60104                 nearCenter = d;
60105               }
60106             });
60107             var image = selection.selectAll('img').data(requests, function (d) {
60108               return d[3];
60109             });
60110             image.exit().style(transformProp, imageTransform).classed('tile-removing', true).classed('tile-center', false).each(function () {
60111               var tile = select(this);
60112               window.setTimeout(function () {
60113                 if (tile.classed('tile-removing')) {
60114                   tile.remove();
60115                 }
60116               }, 300);
60117             });
60118             image.enter().append('img').attr('class', 'tile').attr('draggable', 'false').style('width', _tileSize + 'px').style('height', _tileSize + 'px').attr('src', function (d) {
60119               return d[3];
60120             }).on('error', error).on('load', load).merge(image).style(transformProp, imageTransform).classed('tile-debug', showDebug).classed('tile-removing', false).classed('tile-center', function (d) {
60121               return d === nearCenter;
60122             });
60123             var debug = selection.selectAll('.tile-label-debug').data(showDebug ? requests : [], function (d) {
60124               return d[3];
60125             });
60126             debug.exit().remove();
60127
60128             if (showDebug) {
60129               var debugEnter = debug.enter().append('div').attr('class', 'tile-label-debug');
60130               debugEnter.append('div').attr('class', 'tile-label-debug-coord');
60131               debugEnter.append('div').attr('class', 'tile-label-debug-vintage');
60132               debug = debug.merge(debugEnter);
60133               debug.style(transformProp, debugTransform);
60134               debug.selectAll('.tile-label-debug-coord').html(function (d) {
60135                 return d[2] + ' / ' + d[0] + ' / ' + d[1];
60136               });
60137               debug.selectAll('.tile-label-debug-vintage').each(function (d) {
60138                 var span = select(this);
60139                 var center = context.projection.invert(tileCenter(d));
60140
60141                 _source.getMetadata(center, d, function (err, result) {
60142                   span.html(result && result.vintage && result.vintage.range || _t('info_panels.background.vintage') + ': ' + _t('info_panels.background.unknown'));
60143                 });
60144               });
60145             }
60146           }
60147
60148           background.projection = function (val) {
60149             if (!arguments.length) return _projection;
60150             _projection = val;
60151             return background;
60152           };
60153
60154           background.dimensions = function (val) {
60155             if (!arguments.length) return tiler.size();
60156             tiler.size(val);
60157             return background;
60158           };
60159
60160           background.source = function (val) {
60161             if (!arguments.length) return _source;
60162             _source = val;
60163             _tileSize = _source.tileSize;
60164             _cache = {};
60165             tiler.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
60166             return background;
60167           };
60168
60169           return background;
60170         }
60171
60172         var _imageryIndex = null;
60173         function rendererBackground(context) {
60174           var dispatch = dispatch$8('change');
60175           var detected = utilDetect();
60176           var baseLayer = rendererTileLayer(context).projection(context.projection);
60177           var _isValid = true;
60178           var _overlayLayers = [];
60179           var _brightness = 1;
60180           var _contrast = 1;
60181           var _saturation = 1;
60182           var _sharpness = 1;
60183
60184           function ensureImageryIndex() {
60185             return _mainFileFetcher.get('imagery').then(function (sources) {
60186               if (_imageryIndex) return _imageryIndex;
60187               _imageryIndex = {
60188                 imagery: sources,
60189                 features: {}
60190               }; // use which-polygon to support efficient index and querying for imagery
60191
60192               var features = sources.map(function (source) {
60193                 if (!source.polygon) return null; // workaround for editor-layer-index weirdness..
60194                 // Add an extra array nest to each element in `source.polygon`
60195                 // so the rings are not treated as a bunch of holes:
60196                 // what we have: [ [[outer],[hole],[hole]] ]
60197                 // what we want: [ [[outer]],[[outer]],[[outer]] ]
60198
60199                 var rings = source.polygon.map(function (ring) {
60200                   return [ring];
60201                 });
60202                 var feature = {
60203                   type: 'Feature',
60204                   properties: {
60205                     id: source.id
60206                   },
60207                   geometry: {
60208                     type: 'MultiPolygon',
60209                     coordinates: rings
60210                   }
60211                 };
60212                 _imageryIndex.features[source.id] = feature;
60213                 return feature;
60214               }).filter(Boolean);
60215               _imageryIndex.query = whichPolygon_1({
60216                 type: 'FeatureCollection',
60217                 features: features
60218               }); // Instantiate `rendererBackgroundSource` objects for each source
60219
60220               _imageryIndex.backgrounds = sources.map(function (source) {
60221                 if (source.type === 'bing') {
60222                   return rendererBackgroundSource.Bing(source, dispatch);
60223                 } else if (/^EsriWorldImagery/.test(source.id)) {
60224                   return rendererBackgroundSource.Esri(source);
60225                 } else {
60226                   return rendererBackgroundSource(source);
60227                 }
60228               }); // Add 'None'
60229
60230               _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None()); // Add 'Custom'
60231
60232
60233               var template = corePreferences('background-custom-template') || '';
60234               var custom = rendererBackgroundSource.Custom(template);
60235
60236               _imageryIndex.backgrounds.unshift(custom);
60237
60238               return _imageryIndex;
60239             });
60240           }
60241
60242           function background(selection) {
60243             var currSource = baseLayer.source(); // If we are displaying an Esri basemap at high zoom,
60244             // check its tilemap to see how high the zoom can go
60245
60246             if (context.map().zoom() > 18) {
60247               if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
60248                 var center = context.map().center();
60249                 currSource.fetchTilemap(center);
60250               }
60251             } // Is the imagery valid here? - #4827
60252
60253
60254             var sources = background.sources(context.map().extent());
60255             var wasValid = _isValid;
60256             _isValid = !!sources.filter(function (d) {
60257               return d === currSource;
60258             }).length;
60259
60260             if (wasValid !== _isValid) {
60261               // change in valid status
60262               background.updateImagery();
60263             }
60264
60265             var baseFilter = '';
60266
60267             if (detected.cssfilters) {
60268               if (_brightness !== 1) {
60269                 baseFilter += " brightness(".concat(_brightness, ")");
60270               }
60271
60272               if (_contrast !== 1) {
60273                 baseFilter += " contrast(".concat(_contrast, ")");
60274               }
60275
60276               if (_saturation !== 1) {
60277                 baseFilter += " saturate(".concat(_saturation, ")");
60278               }
60279
60280               if (_sharpness < 1) {
60281                 // gaussian blur
60282                 var blur = d3_interpolateNumber(0.5, 5)(1 - _sharpness);
60283                 baseFilter += " blur(".concat(blur, "px)");
60284               }
60285             }
60286
60287             var base = selection.selectAll('.layer-background').data([0]);
60288             base = base.enter().insert('div', '.layer-data').attr('class', 'layer layer-background').merge(base);
60289
60290             if (detected.cssfilters) {
60291               base.style('filter', baseFilter || null);
60292             } else {
60293               base.style('opacity', _brightness);
60294             }
60295
60296             var imagery = base.selectAll('.layer-imagery').data([0]);
60297             imagery.enter().append('div').attr('class', 'layer layer-imagery').merge(imagery).call(baseLayer);
60298             var maskFilter = '';
60299             var mixBlendMode = '';
60300
60301             if (detected.cssfilters && _sharpness > 1) {
60302               // apply unsharp mask
60303               mixBlendMode = 'overlay';
60304               maskFilter = 'saturate(0) blur(3px) invert(1)';
60305               var contrast = _sharpness - 1;
60306               maskFilter += " contrast(".concat(contrast, ")");
60307               var brightness = d3_interpolateNumber(1, 0.85)(_sharpness - 1);
60308               maskFilter += " brightness(".concat(brightness, ")");
60309             }
60310
60311             var mask = base.selectAll('.layer-unsharp-mask').data(detected.cssfilters && _sharpness > 1 ? [0] : []);
60312             mask.exit().remove();
60313             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);
60314             var overlays = selection.selectAll('.layer-overlay').data(_overlayLayers, function (d) {
60315               return d.source().name();
60316             });
60317             overlays.exit().remove();
60318             overlays.enter().insert('div', '.layer-data').attr('class', 'layer layer-overlay').merge(overlays).each(function (layer, i, nodes) {
60319               return select(nodes[i]).call(layer);
60320             });
60321           }
60322
60323           background.updateImagery = function () {
60324             var currSource = baseLayer.source();
60325             if (context.inIntro() || !currSource) return;
60326
60327             var o = _overlayLayers.filter(function (d) {
60328               return !d.source().isLocatorOverlay() && !d.source().isHidden();
60329             }).map(function (d) {
60330               return d.source().id;
60331             }).join(',');
60332
60333             var meters = geoOffsetToMeters(currSource.offset());
60334             var EPSILON = 0.01;
60335             var x = +meters[0].toFixed(2);
60336             var y = +meters[1].toFixed(2);
60337             var hash = utilStringQs(window.location.hash);
60338             var id = currSource.id;
60339
60340             if (id === 'custom') {
60341               id = "custom:".concat(currSource.template());
60342             }
60343
60344             if (id) {
60345               hash.background = id;
60346             } else {
60347               delete hash.background;
60348             }
60349
60350             if (o) {
60351               hash.overlays = o;
60352             } else {
60353               delete hash.overlays;
60354             }
60355
60356             if (Math.abs(x) > EPSILON || Math.abs(y) > EPSILON) {
60357               hash.offset = "".concat(x, ",").concat(y);
60358             } else {
60359               delete hash.offset;
60360             }
60361
60362             if (!window.mocha) {
60363               window.location.replace('#' + utilQsString(hash, true));
60364             }
60365
60366             var imageryUsed = [];
60367             var photoOverlaysUsed = [];
60368             var currUsed = currSource.imageryUsed();
60369
60370             if (currUsed && _isValid) {
60371               imageryUsed.push(currUsed);
60372             }
60373
60374             _overlayLayers.filter(function (d) {
60375               return !d.source().isLocatorOverlay() && !d.source().isHidden();
60376             }).forEach(function (d) {
60377               return imageryUsed.push(d.source().imageryUsed());
60378             });
60379
60380             var dataLayer = context.layers().layer('data');
60381
60382             if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
60383               imageryUsed.push(dataLayer.getSrc());
60384             }
60385
60386             var photoOverlayLayers = {
60387               streetside: 'Bing Streetside',
60388               mapillary: 'Mapillary Images',
60389               'mapillary-map-features': 'Mapillary Map Features',
60390               'mapillary-signs': 'Mapillary Signs',
60391               openstreetcam: 'OpenStreetCam Images'
60392             };
60393
60394             for (var layerID in photoOverlayLayers) {
60395               var layer = context.layers().layer(layerID);
60396
60397               if (layer && layer.enabled()) {
60398                 photoOverlaysUsed.push(layerID);
60399                 imageryUsed.push(photoOverlayLayers[layerID]);
60400               }
60401             }
60402
60403             context.history().imageryUsed(imageryUsed);
60404             context.history().photoOverlaysUsed(photoOverlaysUsed);
60405           };
60406
60407           var _checkedBlocklists;
60408
60409           background.sources = function (extent, zoom, includeCurrent) {
60410             if (!_imageryIndex) return []; // called before init()?
60411
60412             var visible = {};
60413             (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach(function (d) {
60414               return visible[d.id] = true;
60415             });
60416             var currSource = baseLayer.source();
60417             var osm = context.connection();
60418             var blocklists = osm && osm.imageryBlocklists();
60419
60420             if (blocklists && blocklists !== _checkedBlocklists) {
60421               _imageryIndex.backgrounds.forEach(function (source) {
60422                 source.isBlocked = blocklists.some(function (blocklist) {
60423                   return blocklist.test(source.template());
60424                 });
60425               });
60426
60427               _checkedBlocklists = blocklists;
60428             }
60429
60430             return _imageryIndex.backgrounds.filter(function (source) {
60431               if (includeCurrent && currSource === source) return true; // optionally always include the current imagery
60432
60433               if (source.isBlocked) return false; // even bundled sources may be blocked - #7905
60434
60435               if (!source.polygon) return true; // always include imagery with worldwide coverage
60436
60437               if (zoom && zoom < 6) return false; // optionally exclude local imagery at low zooms
60438
60439               return visible[source.id]; // include imagery visible in given extent
60440             });
60441           };
60442
60443           background.dimensions = function (val) {
60444             if (!val) return;
60445             baseLayer.dimensions(val);
60446
60447             _overlayLayers.forEach(function (layer) {
60448               return layer.dimensions(val);
60449             });
60450           };
60451
60452           background.baseLayerSource = function (d) {
60453             if (!arguments.length) return baseLayer.source(); // test source against OSM imagery blocklists..
60454
60455             var osm = context.connection();
60456             if (!osm) return background;
60457             var blocklists = osm.imageryBlocklists();
60458             var template = d.template();
60459             var fail = false;
60460             var tested = 0;
60461             var regex;
60462
60463             for (var i = 0; i < blocklists.length; i++) {
60464               regex = blocklists[i];
60465               fail = regex.test(template);
60466               tested++;
60467               if (fail) break;
60468             } // ensure at least one test was run.
60469
60470
60471             if (!tested) {
60472               regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
60473               fail = regex.test(template);
60474             }
60475
60476             baseLayer.source(!fail ? d : background.findSource('none'));
60477             dispatch.call('change');
60478             background.updateImagery();
60479             return background;
60480           };
60481
60482           background.findSource = function (id) {
60483             if (!id || !_imageryIndex) return null; // called before init()?
60484
60485             return _imageryIndex.backgrounds.find(function (d) {
60486               return d.id && d.id === id;
60487             });
60488           };
60489
60490           background.bing = function () {
60491             background.baseLayerSource(background.findSource('Bing'));
60492           };
60493
60494           background.showsLayer = function (d) {
60495             var currSource = baseLayer.source();
60496             if (!d || !currSource) return false;
60497             return d.id === currSource.id || _overlayLayers.some(function (layer) {
60498               return d.id === layer.source().id;
60499             });
60500           };
60501
60502           background.overlayLayerSources = function () {
60503             return _overlayLayers.map(function (layer) {
60504               return layer.source();
60505             });
60506           };
60507
60508           background.toggleOverlayLayer = function (d) {
60509             var layer;
60510
60511             for (var i = 0; i < _overlayLayers.length; i++) {
60512               layer = _overlayLayers[i];
60513
60514               if (layer.source() === d) {
60515                 _overlayLayers.splice(i, 1);
60516
60517                 dispatch.call('change');
60518                 background.updateImagery();
60519                 return;
60520               }
60521             }
60522
60523             layer = rendererTileLayer(context).source(d).projection(context.projection).dimensions(baseLayer.dimensions());
60524
60525             _overlayLayers.push(layer);
60526
60527             dispatch.call('change');
60528             background.updateImagery();
60529           };
60530
60531           background.nudge = function (d, zoom) {
60532             var currSource = baseLayer.source();
60533
60534             if (currSource) {
60535               currSource.nudge(d, zoom);
60536               dispatch.call('change');
60537               background.updateImagery();
60538             }
60539
60540             return background;
60541           };
60542
60543           background.offset = function (d) {
60544             var currSource = baseLayer.source();
60545
60546             if (!arguments.length) {
60547               return currSource && currSource.offset() || [0, 0];
60548             }
60549
60550             if (currSource) {
60551               currSource.offset(d);
60552               dispatch.call('change');
60553               background.updateImagery();
60554             }
60555
60556             return background;
60557           };
60558
60559           background.brightness = function (d) {
60560             if (!arguments.length) return _brightness;
60561             _brightness = d;
60562             if (context.mode()) dispatch.call('change');
60563             return background;
60564           };
60565
60566           background.contrast = function (d) {
60567             if (!arguments.length) return _contrast;
60568             _contrast = d;
60569             if (context.mode()) dispatch.call('change');
60570             return background;
60571           };
60572
60573           background.saturation = function (d) {
60574             if (!arguments.length) return _saturation;
60575             _saturation = d;
60576             if (context.mode()) dispatch.call('change');
60577             return background;
60578           };
60579
60580           background.sharpness = function (d) {
60581             if (!arguments.length) return _sharpness;
60582             _sharpness = d;
60583             if (context.mode()) dispatch.call('change');
60584             return background;
60585           };
60586
60587           var _loadPromise;
60588
60589           background.ensureLoaded = function () {
60590             if (_loadPromise) return _loadPromise;
60591
60592             function parseMapParams(qmap) {
60593               if (!qmap) return false;
60594               var params = qmap.split('/').map(Number);
60595               if (params.length < 3 || params.some(isNaN)) return false;
60596               return geoExtent([params[2], params[1]]); // lon,lat
60597             }
60598
60599             var hash = utilStringQs(window.location.hash);
60600             var requested = hash.background || hash.layer;
60601             var extent = parseMapParams(hash.map);
60602             return _loadPromise = ensureImageryIndex().then(function (imageryIndex) {
60603               var first = imageryIndex.backgrounds.length && imageryIndex.backgrounds[0];
60604               var best;
60605
60606               if (!requested && extent) {
60607                 best = background.sources(extent).find(function (s) {
60608                   return s.best();
60609                 });
60610               } // Decide which background layer to display
60611
60612
60613               if (requested && requested.indexOf('custom:') === 0) {
60614                 var template = requested.replace(/^custom:/, '');
60615                 var custom = background.findSource('custom');
60616                 background.baseLayerSource(custom.template(template));
60617                 corePreferences('background-custom-template', template);
60618               } else {
60619                 background.baseLayerSource(background.findSource(requested) || best || background.findSource(corePreferences('background-last-used')) || background.findSource('Bing') || first || background.findSource('none'));
60620               }
60621
60622               var locator = imageryIndex.backgrounds.find(function (d) {
60623                 return d.overlay && d["default"];
60624               });
60625
60626               if (locator) {
60627                 background.toggleOverlayLayer(locator);
60628               }
60629
60630               var overlays = (hash.overlays || '').split(',');
60631               overlays.forEach(function (overlay) {
60632                 overlay = background.findSource(overlay);
60633
60634                 if (overlay) {
60635                   background.toggleOverlayLayer(overlay);
60636                 }
60637               });
60638
60639               if (hash.gpx) {
60640                 var gpx = context.layers().layer('data');
60641
60642                 if (gpx) {
60643                   gpx.url(hash.gpx, '.gpx');
60644                 }
60645               }
60646
60647               if (hash.offset) {
60648                 var offset = hash.offset.replace(/;/g, ',').split(',').map(function (n) {
60649                   return !isNaN(n) && n;
60650                 });
60651
60652                 if (offset.length === 2) {
60653                   background.offset(geoMetersToOffset(offset));
60654                 }
60655               }
60656             })["catch"](function () {
60657               /* ignore */
60658             });
60659           };
60660
60661           return utilRebind(background, dispatch, 'on');
60662         }
60663
60664         function rendererFeatures(context) {
60665           var dispatch = dispatch$8('change', 'redraw');
60666           var features = utilRebind({}, dispatch, 'on');
60667
60668           var _deferred = new Set();
60669
60670           var traffic_roads = {
60671             'motorway': true,
60672             'motorway_link': true,
60673             'trunk': true,
60674             'trunk_link': true,
60675             'primary': true,
60676             'primary_link': true,
60677             'secondary': true,
60678             'secondary_link': true,
60679             'tertiary': true,
60680             'tertiary_link': true,
60681             'residential': true,
60682             'unclassified': true,
60683             'living_street': true
60684           };
60685           var service_roads = {
60686             'service': true,
60687             'road': true,
60688             'track': true
60689           };
60690           var paths = {
60691             'path': true,
60692             'footway': true,
60693             'cycleway': true,
60694             'bridleway': true,
60695             'steps': true,
60696             'pedestrian': true
60697           };
60698           var past_futures = {
60699             'proposed': true,
60700             'construction': true,
60701             'abandoned': true,
60702             'dismantled': true,
60703             'disused': true,
60704             'razed': true,
60705             'demolished': true,
60706             'obliterated': true
60707           };
60708           var _cullFactor = 1;
60709           var _cache = {};
60710           var _rules = {};
60711           var _stats = {};
60712           var _keys = [];
60713           var _hidden = [];
60714           var _forceVisible = {};
60715
60716           function update() {
60717             if (!window.mocha) {
60718               var hash = utilStringQs(window.location.hash);
60719               var disabled = features.disabled();
60720
60721               if (disabled.length) {
60722                 hash.disable_features = disabled.join(',');
60723               } else {
60724                 delete hash.disable_features;
60725               }
60726
60727               window.location.replace('#' + utilQsString(hash, true));
60728               corePreferences('disabled-features', disabled.join(','));
60729             }
60730
60731             _hidden = features.hidden();
60732             dispatch.call('change');
60733             dispatch.call('redraw');
60734           }
60735
60736           function defineRule(k, filter, max) {
60737             var isEnabled = true;
60738
60739             _keys.push(k);
60740
60741             _rules[k] = {
60742               filter: filter,
60743               enabled: isEnabled,
60744               // whether the user wants it enabled..
60745               count: 0,
60746               currentMax: max || Infinity,
60747               defaultMax: max || Infinity,
60748               enable: function enable() {
60749                 this.enabled = true;
60750                 this.currentMax = this.defaultMax;
60751               },
60752               disable: function disable() {
60753                 this.enabled = false;
60754                 this.currentMax = 0;
60755               },
60756               hidden: function hidden() {
60757                 return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
60758               },
60759               autoHidden: function autoHidden() {
60760                 return this.hidden() && this.currentMax > 0;
60761               }
60762             };
60763           }
60764
60765           defineRule('points', function isPoint(tags, geometry) {
60766             return geometry === 'point';
60767           }, 200);
60768           defineRule('traffic_roads', function isTrafficRoad(tags) {
60769             return traffic_roads[tags.highway];
60770           });
60771           defineRule('service_roads', function isServiceRoad(tags) {
60772             return service_roads[tags.highway];
60773           });
60774           defineRule('paths', function isPath(tags) {
60775             return paths[tags.highway];
60776           });
60777           defineRule('buildings', function isBuilding(tags) {
60778             return !!tags.building && tags.building !== 'no' || tags.parking === 'multi-storey' || tags.parking === 'sheds' || tags.parking === 'carports' || tags.parking === 'garage_boxes';
60779           }, 250);
60780           defineRule('building_parts', function isBuildingPart(tags) {
60781             return tags['building:part'];
60782           });
60783           defineRule('indoor', function isIndoor(tags) {
60784             return tags.indoor;
60785           });
60786           defineRule('landuse', function isLanduse(tags, geometry) {
60787             return geometry === 'area' && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
60788           });
60789           defineRule('boundaries', function isBoundary(tags) {
60790             return !!tags.boundary && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway] || tags.waterway || tags.railway || tags.landuse || tags.natural || tags.building || tags.power);
60791           });
60792           defineRule('water', function isWater(tags) {
60793             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';
60794           });
60795           defineRule('rail', function isRail(tags) {
60796             return (!!tags.railway || tags.landuse === 'railway') && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
60797           });
60798           defineRule('pistes', function isPiste(tags) {
60799             return tags['piste:type'];
60800           });
60801           defineRule('aerialways', function isPiste(tags) {
60802             return tags.aerialway && tags.aerialway !== 'yes' && tags.aerialway !== 'station';
60803           });
60804           defineRule('power', function isPower(tags) {
60805             return !!tags.power;
60806           }); // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
60807
60808           defineRule('past_future', function isPastFuture(tags) {
60809             if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
60810               return false;
60811             }
60812
60813             var strings = Object.keys(tags);
60814
60815             for (var i = 0; i < strings.length; i++) {
60816               var s = strings[i];
60817
60818               if (past_futures[s] || past_futures[tags[s]]) {
60819                 return true;
60820               }
60821             }
60822
60823             return false;
60824           }); // Lines or areas that don't match another feature filter.
60825           // IMPORTANT: The 'others' feature must be the last one defined,
60826           //   so that code in getMatches can skip this test if `hasMatch = true`
60827
60828           defineRule('others', function isOther(tags, geometry) {
60829             return geometry === 'line' || geometry === 'area';
60830           });
60831
60832           features.features = function () {
60833             return _rules;
60834           };
60835
60836           features.keys = function () {
60837             return _keys;
60838           };
60839
60840           features.enabled = function (k) {
60841             if (!arguments.length) {
60842               return _keys.filter(function (k) {
60843                 return _rules[k].enabled;
60844               });
60845             }
60846
60847             return _rules[k] && _rules[k].enabled;
60848           };
60849
60850           features.disabled = function (k) {
60851             if (!arguments.length) {
60852               return _keys.filter(function (k) {
60853                 return !_rules[k].enabled;
60854               });
60855             }
60856
60857             return _rules[k] && !_rules[k].enabled;
60858           };
60859
60860           features.hidden = function (k) {
60861             if (!arguments.length) {
60862               return _keys.filter(function (k) {
60863                 return _rules[k].hidden();
60864               });
60865             }
60866
60867             return _rules[k] && _rules[k].hidden();
60868           };
60869
60870           features.autoHidden = function (k) {
60871             if (!arguments.length) {
60872               return _keys.filter(function (k) {
60873                 return _rules[k].autoHidden();
60874               });
60875             }
60876
60877             return _rules[k] && _rules[k].autoHidden();
60878           };
60879
60880           features.enable = function (k) {
60881             if (_rules[k] && !_rules[k].enabled) {
60882               _rules[k].enable();
60883
60884               update();
60885             }
60886           };
60887
60888           features.enableAll = function () {
60889             var didEnable = false;
60890
60891             for (var k in _rules) {
60892               if (!_rules[k].enabled) {
60893                 didEnable = true;
60894
60895                 _rules[k].enable();
60896               }
60897             }
60898
60899             if (didEnable) update();
60900           };
60901
60902           features.disable = function (k) {
60903             if (_rules[k] && _rules[k].enabled) {
60904               _rules[k].disable();
60905
60906               update();
60907             }
60908           };
60909
60910           features.disableAll = function () {
60911             var didDisable = false;
60912
60913             for (var k in _rules) {
60914               if (_rules[k].enabled) {
60915                 didDisable = true;
60916
60917                 _rules[k].disable();
60918               }
60919             }
60920
60921             if (didDisable) update();
60922           };
60923
60924           features.toggle = function (k) {
60925             if (_rules[k]) {
60926               (function (f) {
60927                 return f.enabled ? f.disable() : f.enable();
60928               })(_rules[k]);
60929
60930               update();
60931             }
60932           };
60933
60934           features.resetStats = function () {
60935             for (var i = 0; i < _keys.length; i++) {
60936               _rules[_keys[i]].count = 0;
60937             }
60938
60939             dispatch.call('change');
60940           };
60941
60942           features.gatherStats = function (d, resolver, dimensions) {
60943             var needsRedraw = false;
60944             var types = utilArrayGroupBy(d, 'type');
60945             var entities = [].concat(types.relation || [], types.way || [], types.node || []);
60946             var currHidden, geometry, matches, i, j;
60947
60948             for (i = 0; i < _keys.length; i++) {
60949               _rules[_keys[i]].count = 0;
60950             } // adjust the threshold for point/building culling based on viewport size..
60951             // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
60952
60953
60954             _cullFactor = dimensions[0] * dimensions[1] / 1000000;
60955
60956             for (i = 0; i < entities.length; i++) {
60957               geometry = entities[i].geometry(resolver);
60958               matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
60959
60960               for (j = 0; j < matches.length; j++) {
60961                 _rules[matches[j]].count++;
60962               }
60963             }
60964
60965             currHidden = features.hidden();
60966
60967             if (currHidden !== _hidden) {
60968               _hidden = currHidden;
60969               needsRedraw = true;
60970               dispatch.call('change');
60971             }
60972
60973             return needsRedraw;
60974           };
60975
60976           features.stats = function () {
60977             for (var i = 0; i < _keys.length; i++) {
60978               _stats[_keys[i]] = _rules[_keys[i]].count;
60979             }
60980
60981             return _stats;
60982           };
60983
60984           features.clear = function (d) {
60985             for (var i = 0; i < d.length; i++) {
60986               features.clearEntity(d[i]);
60987             }
60988           };
60989
60990           features.clearEntity = function (entity) {
60991             delete _cache[osmEntity.key(entity)];
60992           };
60993
60994           features.reset = function () {
60995             Array.from(_deferred).forEach(function (handle) {
60996               window.cancelIdleCallback(handle);
60997
60998               _deferred["delete"](handle);
60999             });
61000             _cache = {};
61001           }; // only certain relations are worth checking
61002
61003
61004           function relationShouldBeChecked(relation) {
61005             // multipolygon features have `area` geometry and aren't checked here
61006             return relation.tags.type === 'boundary';
61007           }
61008
61009           features.getMatches = function (entity, resolver, geometry) {
61010             if (geometry === 'vertex' || geometry === 'relation' && !relationShouldBeChecked(entity)) return {};
61011             var ent = osmEntity.key(entity);
61012
61013             if (!_cache[ent]) {
61014               _cache[ent] = {};
61015             }
61016
61017             if (!_cache[ent].matches) {
61018               var matches = {};
61019               var hasMatch = false;
61020
61021               for (var i = 0; i < _keys.length; i++) {
61022                 if (_keys[i] === 'others') {
61023                   if (hasMatch) continue; // If an entity...
61024                   //   1. is a way that hasn't matched other 'interesting' feature rules,
61025
61026                   if (entity.type === 'way') {
61027                     var parents = features.getParents(entity, resolver, geometry); //   2a. belongs only to a single multipolygon relation
61028
61029                     if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
61030                     parents.length > 0 && parents.every(function (parent) {
61031                       return parent.tags.type === 'boundary';
61032                     })) {
61033                       // ...then match whatever feature rules the parent relation has matched.
61034                       // see #2548, #2887
61035                       //
61036                       // IMPORTANT:
61037                       // For this to work, getMatches must be called on relations before ways.
61038                       //
61039                       var pkey = osmEntity.key(parents[0]);
61040
61041                       if (_cache[pkey] && _cache[pkey].matches) {
61042                         matches = Object.assign({}, _cache[pkey].matches); // shallow copy
61043
61044                         continue;
61045                       }
61046                     }
61047                   }
61048                 }
61049
61050                 if (_rules[_keys[i]].filter(entity.tags, geometry)) {
61051                   matches[_keys[i]] = hasMatch = true;
61052                 }
61053               }
61054
61055               _cache[ent].matches = matches;
61056             }
61057
61058             return _cache[ent].matches;
61059           };
61060
61061           features.getParents = function (entity, resolver, geometry) {
61062             if (geometry === 'point') return [];
61063             var ent = osmEntity.key(entity);
61064
61065             if (!_cache[ent]) {
61066               _cache[ent] = {};
61067             }
61068
61069             if (!_cache[ent].parents) {
61070               var parents = [];
61071
61072               if (geometry === 'vertex') {
61073                 parents = resolver.parentWays(entity);
61074               } else {
61075                 // 'line', 'area', 'relation'
61076                 parents = resolver.parentRelations(entity);
61077               }
61078
61079               _cache[ent].parents = parents;
61080             }
61081
61082             return _cache[ent].parents;
61083           };
61084
61085           features.isHiddenPreset = function (preset, geometry) {
61086             if (!_hidden.length) return false;
61087             if (!preset.tags) return false;
61088             var test = preset.setTags({}, geometry);
61089
61090             for (var key in _rules) {
61091               if (_rules[key].filter(test, geometry)) {
61092                 if (_hidden.indexOf(key) !== -1) {
61093                   return key;
61094                 }
61095
61096                 return false;
61097               }
61098             }
61099
61100             return false;
61101           };
61102
61103           features.isHiddenFeature = function (entity, resolver, geometry) {
61104             if (!_hidden.length) return false;
61105             if (!entity.version) return false;
61106             if (_forceVisible[entity.id]) return false;
61107             var matches = Object.keys(features.getMatches(entity, resolver, geometry));
61108             return matches.length && matches.every(function (k) {
61109               return features.hidden(k);
61110             });
61111           };
61112
61113           features.isHiddenChild = function (entity, resolver, geometry) {
61114             if (!_hidden.length) return false;
61115             if (!entity.version || geometry === 'point') return false;
61116             if (_forceVisible[entity.id]) return false;
61117             var parents = features.getParents(entity, resolver, geometry);
61118             if (!parents.length) return false;
61119
61120             for (var i = 0; i < parents.length; i++) {
61121               if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
61122                 return false;
61123               }
61124             }
61125
61126             return true;
61127           };
61128
61129           features.hasHiddenConnections = function (entity, resolver) {
61130             if (!_hidden.length) return false;
61131             var childNodes, connections;
61132
61133             if (entity.type === 'midpoint') {
61134               childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
61135               connections = [];
61136             } else {
61137               childNodes = entity.nodes ? resolver.childNodes(entity) : [];
61138               connections = features.getParents(entity, resolver, entity.geometry(resolver));
61139             } // gather ways connected to child nodes..
61140
61141
61142             connections = childNodes.reduce(function (result, e) {
61143               return resolver.isShared(e) ? utilArrayUnion(result, resolver.parentWays(e)) : result;
61144             }, connections);
61145             return connections.some(function (e) {
61146               return features.isHidden(e, resolver, e.geometry(resolver));
61147             });
61148           };
61149
61150           features.isHidden = function (entity, resolver, geometry) {
61151             if (!_hidden.length) return false;
61152             if (!entity.version) return false;
61153             var fn = geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature;
61154             return fn(entity, resolver, geometry);
61155           };
61156
61157           features.filter = function (d, resolver) {
61158             if (!_hidden.length) return d;
61159             var result = [];
61160
61161             for (var i = 0; i < d.length; i++) {
61162               var entity = d[i];
61163
61164               if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
61165                 result.push(entity);
61166               }
61167             }
61168
61169             return result;
61170           };
61171
61172           features.forceVisible = function (entityIDs) {
61173             if (!arguments.length) return Object.keys(_forceVisible);
61174             _forceVisible = {};
61175
61176             for (var i = 0; i < entityIDs.length; i++) {
61177               _forceVisible[entityIDs[i]] = true;
61178               var entity = context.hasEntity(entityIDs[i]);
61179
61180               if (entity && entity.type === 'relation') {
61181                 // also show relation members (one level deep)
61182                 for (var j in entity.members) {
61183                   _forceVisible[entity.members[j].id] = true;
61184                 }
61185               }
61186             }
61187
61188             return features;
61189           };
61190
61191           features.init = function () {
61192             var storage = corePreferences('disabled-features');
61193
61194             if (storage) {
61195               var storageDisabled = storage.replace(/;/g, ',').split(',');
61196               storageDisabled.forEach(features.disable);
61197             }
61198
61199             var hash = utilStringQs(window.location.hash);
61200
61201             if (hash.disable_features) {
61202               var hashDisabled = hash.disable_features.replace(/;/g, ',').split(',');
61203               hashDisabled.forEach(features.disable);
61204             }
61205           }; // warm up the feature matching cache upon merging fetched data
61206
61207
61208           context.history().on('merge.features', function (newEntities) {
61209             if (!newEntities) return;
61210             var handle = window.requestIdleCallback(function () {
61211               var graph = context.graph();
61212               var types = utilArrayGroupBy(newEntities, 'type'); // ensure that getMatches is called on relations before ways
61213
61214               var entities = [].concat(types.relation || [], types.way || [], types.node || []);
61215
61216               for (var i = 0; i < entities.length; i++) {
61217                 var geometry = entities[i].geometry(graph);
61218                 features.getMatches(entities[i], graph, geometry);
61219               }
61220             });
61221
61222             _deferred.add(handle);
61223           });
61224           return features;
61225         }
61226
61227         /** Error message constants. */
61228
61229         var FUNC_ERROR_TEXT = 'Expected a function';
61230         /**
61231          * Creates a throttled function that only invokes `func` at most once per
61232          * every `wait` milliseconds. The throttled function comes with a `cancel`
61233          * method to cancel delayed `func` invocations and a `flush` method to
61234          * immediately invoke them. Provide `options` to indicate whether `func`
61235          * should be invoked on the leading and/or trailing edge of the `wait`
61236          * timeout. The `func` is invoked with the last arguments provided to the
61237          * throttled function. Subsequent calls to the throttled function return the
61238          * result of the last `func` invocation.
61239          *
61240          * **Note:** If `leading` and `trailing` options are `true`, `func` is
61241          * invoked on the trailing edge of the timeout only if the throttled function
61242          * is invoked more than once during the `wait` timeout.
61243          *
61244          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
61245          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
61246          *
61247          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
61248          * for details over the differences between `_.throttle` and `_.debounce`.
61249          *
61250          * @static
61251          * @memberOf _
61252          * @since 0.1.0
61253          * @category Function
61254          * @param {Function} func The function to throttle.
61255          * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
61256          * @param {Object} [options={}] The options object.
61257          * @param {boolean} [options.leading=true]
61258          *  Specify invoking on the leading edge of the timeout.
61259          * @param {boolean} [options.trailing=true]
61260          *  Specify invoking on the trailing edge of the timeout.
61261          * @returns {Function} Returns the new throttled function.
61262          * @example
61263          *
61264          * // Avoid excessively updating the position while scrolling.
61265          * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
61266          *
61267          * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
61268          * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
61269          * jQuery(element).on('click', throttled);
61270          *
61271          * // Cancel the trailing throttled invocation.
61272          * jQuery(window).on('popstate', throttled.cancel);
61273          */
61274
61275         function throttle(func, wait, options) {
61276           var leading = true,
61277               trailing = true;
61278
61279           if (typeof func != 'function') {
61280             throw new TypeError(FUNC_ERROR_TEXT);
61281           }
61282
61283           if (isObject$2(options)) {
61284             leading = 'leading' in options ? !!options.leading : leading;
61285             trailing = 'trailing' in options ? !!options.trailing : trailing;
61286           }
61287
61288           return debounce(func, wait, {
61289             'leading': leading,
61290             'maxWait': wait,
61291             'trailing': trailing
61292           });
61293         }
61294
61295         //
61296         // - the activeID - nope
61297         // - 1 away (adjacent) to the activeID - yes (vertices will be merged)
61298         // - 2 away from the activeID - nope (would create a self intersecting segment)
61299         // - all others on a linear way - yes
61300         // - all others on a closed way - nope (would create a self intersecting polygon)
61301         //
61302         // returns
61303         // 0 = active vertex - no touch/connect
61304         // 1 = passive vertex - yes touch/connect
61305         // 2 = adjacent vertex - yes but pay attention segmenting a line here
61306         //
61307
61308         function svgPassiveVertex(node, graph, activeID) {
61309           if (!activeID) return 1;
61310           if (activeID === node.id) return 0;
61311           var parents = graph.parentWays(node);
61312           var i, j, nodes, isClosed, ix1, ix2, ix3, ix4, max;
61313
61314           for (i = 0; i < parents.length; i++) {
61315             nodes = parents[i].nodes;
61316             isClosed = parents[i].isClosed();
61317
61318             for (j = 0; j < nodes.length; j++) {
61319               // find this vertex, look nearby
61320               if (nodes[j] === node.id) {
61321                 ix1 = j - 2;
61322                 ix2 = j - 1;
61323                 ix3 = j + 1;
61324                 ix4 = j + 2;
61325
61326                 if (isClosed) {
61327                   // wraparound if needed
61328                   max = nodes.length - 1;
61329                   if (ix1 < 0) ix1 = max + ix1;
61330                   if (ix2 < 0) ix2 = max + ix2;
61331                   if (ix3 > max) ix3 = ix3 - max;
61332                   if (ix4 > max) ix4 = ix4 - max;
61333                 }
61334
61335                 if (nodes[ix1] === activeID) return 0; // no - prevent self intersect
61336                 else if (nodes[ix2] === activeID) return 2; // ok - adjacent
61337                   else if (nodes[ix3] === activeID) return 2; // ok - adjacent
61338                     else if (nodes[ix4] === activeID) return 0; // no - prevent self intersect
61339                       else if (isClosed && nodes.indexOf(activeID) !== -1) return 0; // no - prevent self intersect
61340               }
61341             }
61342           }
61343
61344           return 1; // ok
61345         }
61346         function svgMarkerSegments(projection, graph, dt, shouldReverse, bothDirections) {
61347           return function (entity) {
61348             var i = 0;
61349             var offset = dt;
61350             var segments = [];
61351             var clip = d3_geoIdentity().clipExtent(projection.clipExtent()).stream;
61352             var coordinates = graph.childNodes(entity).map(function (n) {
61353               return n.loc;
61354             });
61355             var a, b;
61356
61357             if (shouldReverse(entity)) {
61358               coordinates.reverse();
61359             }
61360
61361             d3_geoStream({
61362               type: 'LineString',
61363               coordinates: coordinates
61364             }, projection.stream(clip({
61365               lineStart: function lineStart() {},
61366               lineEnd: function lineEnd() {
61367                 a = null;
61368               },
61369               point: function point(x, y) {
61370                 b = [x, y];
61371
61372                 if (a) {
61373                   var span = geoVecLength(a, b) - offset;
61374
61375                   if (span >= 0) {
61376                     var heading = geoVecAngle(a, b);
61377                     var dx = dt * Math.cos(heading);
61378                     var dy = dt * Math.sin(heading);
61379                     var p = [a[0] + offset * Math.cos(heading), a[1] + offset * Math.sin(heading)]; // gather coordinates
61380
61381                     var coord = [a, p];
61382
61383                     for (span -= dt; span >= 0; span -= dt) {
61384                       p = geoVecAdd(p, [dx, dy]);
61385                       coord.push(p);
61386                     }
61387
61388                     coord.push(b); // generate svg paths
61389
61390                     var segment = '';
61391                     var j;
61392
61393                     for (j = 0; j < coord.length; j++) {
61394                       segment += (j === 0 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
61395                     }
61396
61397                     segments.push({
61398                       id: entity.id,
61399                       index: i++,
61400                       d: segment
61401                     });
61402
61403                     if (bothDirections(entity)) {
61404                       segment = '';
61405
61406                       for (j = coord.length - 1; j >= 0; j--) {
61407                         segment += (j === coord.length - 1 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
61408                       }
61409
61410                       segments.push({
61411                         id: entity.id,
61412                         index: i++,
61413                         d: segment
61414                       });
61415                     }
61416                   }
61417
61418                   offset = -span;
61419                 }
61420
61421                 a = b;
61422               }
61423             })));
61424             return segments;
61425           };
61426         }
61427         function svgPath(projection, graph, isArea) {
61428           // Explanation of magic numbers:
61429           // "padding" here allows space for strokes to extend beyond the viewport,
61430           // so that the stroke isn't drawn along the edge of the viewport when
61431           // the shape is clipped.
61432           //
61433           // When drawing lines, pad viewport by 5px.
61434           // When drawing areas, pad viewport by 65px in each direction to allow
61435           // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
61436           var cache = {};
61437           var padding = isArea ? 65 : 5;
61438           var viewport = projection.clipExtent();
61439           var paddedExtent = [[viewport[0][0] - padding, viewport[0][1] - padding], [viewport[1][0] + padding, viewport[1][1] + padding]];
61440           var clip = d3_geoIdentity().clipExtent(paddedExtent).stream;
61441           var project = projection.stream;
61442           var path = d3_geoPath().projection({
61443             stream: function stream(output) {
61444               return project(clip(output));
61445             }
61446           });
61447
61448           var svgpath = function svgpath(entity) {
61449             if (entity.id in cache) {
61450               return cache[entity.id];
61451             } else {
61452               return cache[entity.id] = path(entity.asGeoJSON(graph));
61453             }
61454           };
61455
61456           svgpath.geojson = function (d) {
61457             if (d.__featurehash__ !== undefined) {
61458               if (d.__featurehash__ in cache) {
61459                 return cache[d.__featurehash__];
61460               } else {
61461                 return cache[d.__featurehash__] = path(d);
61462               }
61463             } else {
61464               return path(d);
61465             }
61466           };
61467
61468           return svgpath;
61469         }
61470         function svgPointTransform(projection) {
61471           var svgpoint = function svgpoint(entity) {
61472             // http://jsperf.com/short-array-join
61473             var pt = projection(entity.loc);
61474             return 'translate(' + pt[0] + ',' + pt[1] + ')';
61475           };
61476
61477           svgpoint.geojson = function (d) {
61478             return svgpoint(d.properties.entity);
61479           };
61480
61481           return svgpoint;
61482         }
61483         function svgRelationMemberTags(graph) {
61484           return function (entity) {
61485             var tags = entity.tags;
61486             var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
61487             graph.parentRelations(entity).forEach(function (relation) {
61488               var type = relation.tags.type;
61489
61490               if (type === 'multipolygon' && shouldCopyMultipolygonTags || type === 'boundary') {
61491                 tags = Object.assign({}, relation.tags, tags);
61492               }
61493             });
61494             return tags;
61495           };
61496         }
61497         function svgSegmentWay(way, graph, activeID) {
61498           // When there is no activeID, we can memoize this expensive computation
61499           if (activeID === undefined) {
61500             return graph["transient"](way, 'waySegments', getWaySegments);
61501           } else {
61502             return getWaySegments();
61503           }
61504
61505           function getWaySegments() {
61506             var isActiveWay = way.nodes.indexOf(activeID) !== -1;
61507             var features = {
61508               passive: [],
61509               active: []
61510             };
61511             var start = {};
61512             var end = {};
61513             var node, type;
61514
61515             for (var i = 0; i < way.nodes.length; i++) {
61516               node = graph.entity(way.nodes[i]);
61517               type = svgPassiveVertex(node, graph, activeID);
61518               end = {
61519                 node: node,
61520                 type: type
61521               };
61522
61523               if (start.type !== undefined) {
61524                 if (start.node.id === activeID || end.node.id === activeID) ; else if (isActiveWay && (start.type === 2 || end.type === 2)) {
61525                   // one adjacent vertex
61526                   pushActive(start, end, i);
61527                 } else if (start.type === 0 && end.type === 0) {
61528                   // both active vertices
61529                   pushActive(start, end, i);
61530                 } else {
61531                   pushPassive(start, end, i);
61532                 }
61533               }
61534
61535               start = end;
61536             }
61537
61538             return features;
61539
61540             function pushActive(start, end, index) {
61541               features.active.push({
61542                 type: 'Feature',
61543                 id: way.id + '-' + index + '-nope',
61544                 properties: {
61545                   nope: true,
61546                   target: true,
61547                   entity: way,
61548                   nodes: [start.node, end.node],
61549                   index: index
61550                 },
61551                 geometry: {
61552                   type: 'LineString',
61553                   coordinates: [start.node.loc, end.node.loc]
61554                 }
61555               });
61556             }
61557
61558             function pushPassive(start, end, index) {
61559               features.passive.push({
61560                 type: 'Feature',
61561                 id: way.id + '-' + index,
61562                 properties: {
61563                   target: true,
61564                   entity: way,
61565                   nodes: [start.node, end.node],
61566                   index: index
61567                 },
61568                 geometry: {
61569                   type: 'LineString',
61570                   coordinates: [start.node.loc, end.node.loc]
61571                 }
61572               });
61573             }
61574           }
61575         }
61576
61577         function svgTagClasses() {
61578           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'];
61579           var statuses = [// nonexistent, might be built
61580           'proposed', 'planned', // under maintentance or between groundbreaking and opening
61581           'construction', // existent but not functional
61582           'disused', // dilapidated to nonexistent
61583           'abandoned', // nonexistent, still may appear in imagery
61584           'dismantled', 'razed', 'demolished', 'obliterated', // existent occasionally, e.g. stormwater drainage basin
61585           'intermittent'];
61586           var secondaries = ['oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier', 'surface', 'tracktype', 'footway', 'crossing', 'service', 'sport', 'public_transport', 'location', 'parking', 'golf', 'type', 'leisure', 'man_made', 'indoor'];
61587
61588           var _tags = function _tags(entity) {
61589             return entity.tags;
61590           };
61591
61592           var tagClasses = function tagClasses(selection) {
61593             selection.each(function tagClassesEach(entity) {
61594               var value = this.className;
61595
61596               if (value.baseVal !== undefined) {
61597                 value = value.baseVal;
61598               }
61599
61600               var t = _tags(entity);
61601
61602               var computed = tagClasses.getClassesString(t, value);
61603
61604               if (computed !== value) {
61605                 select(this).attr('class', computed);
61606               }
61607             });
61608           };
61609
61610           tagClasses.getClassesString = function (t, value) {
61611             var primary, status;
61612             var i, j, k, v; // in some situations we want to render perimeter strokes a certain way
61613
61614             var overrideGeometry;
61615
61616             if (/\bstroke\b/.test(value)) {
61617               if (!!t.barrier && t.barrier !== 'no') {
61618                 overrideGeometry = 'line';
61619               }
61620             } // preserve base classes (nothing with `tag-`)
61621
61622
61623             var classes = value.trim().split(/\s+/).filter(function (klass) {
61624               return klass.length && !/^tag-/.test(klass);
61625             }).map(function (klass) {
61626               // special overrides for some perimeter strokes
61627               return klass === 'line' || klass === 'area' ? overrideGeometry || klass : klass;
61628             }); // pick at most one primary classification tag..
61629
61630             for (i = 0; i < primaries.length; i++) {
61631               k = primaries[i];
61632               v = t[k];
61633               if (!v || v === 'no') continue;
61634
61635               if (k === 'piste:type') {
61636                 // avoid a ':' in the class name
61637                 k = 'piste';
61638               } else if (k === 'building:part') {
61639                 // avoid a ':' in the class name
61640                 k = 'building_part';
61641               }
61642
61643               primary = k;
61644
61645               if (statuses.indexOf(v) !== -1) {
61646                 // e.g. `railway=abandoned`
61647                 status = v;
61648                 classes.push('tag-' + k);
61649               } else {
61650                 classes.push('tag-' + k);
61651                 classes.push('tag-' + k + '-' + v);
61652               }
61653
61654               break;
61655             }
61656
61657             if (!primary) {
61658               for (i = 0; i < statuses.length; i++) {
61659                 for (j = 0; j < primaries.length; j++) {
61660                   k = statuses[i] + ':' + primaries[j]; // e.g. `demolished:building=yes`
61661
61662                   v = t[k];
61663                   if (!v || v === 'no') continue;
61664                   status = statuses[i];
61665                   break;
61666                 }
61667               }
61668             } // add at most one status tag, only if relates to primary tag..
61669
61670
61671             if (!status) {
61672               for (i = 0; i < statuses.length; i++) {
61673                 k = statuses[i];
61674                 v = t[k];
61675                 if (!v || v === 'no') continue;
61676
61677                 if (v === 'yes') {
61678                   // e.g. `railway=rail + abandoned=yes`
61679                   status = k;
61680                 } else if (primary && primary === v) {
61681                   // e.g. `railway=rail + abandoned=railway`
61682                   status = k;
61683                 } else if (!primary && primaries.indexOf(v) !== -1) {
61684                   // e.g. `abandoned=railway`
61685                   status = k;
61686                   primary = v;
61687                   classes.push('tag-' + v);
61688                 } // else ignore e.g.  `highway=path + abandoned=railway`
61689
61690
61691                 if (status) break;
61692               }
61693             }
61694
61695             if (status) {
61696               classes.push('tag-status');
61697               classes.push('tag-status-' + status);
61698             } // add any secondary tags
61699
61700
61701             for (i = 0; i < secondaries.length; i++) {
61702               k = secondaries[i];
61703               v = t[k];
61704               if (!v || v === 'no' || k === primary) continue;
61705               classes.push('tag-' + k);
61706               classes.push('tag-' + k + '-' + v);
61707             } // For highways, look for surface tagging..
61708
61709
61710             if (primary === 'highway' && !osmPathHighwayTagValues[t.highway] || primary === 'aeroway') {
61711               var surface = t.highway === 'track' ? 'unpaved' : 'paved';
61712
61713               for (k in t) {
61714                 v = t[k];
61715
61716                 if (k in osmPavedTags) {
61717                   surface = osmPavedTags[k][v] ? 'paved' : 'unpaved';
61718                 }
61719
61720                 if (k in osmSemipavedTags && !!osmSemipavedTags[k][v]) {
61721                   surface = 'semipaved';
61722                 }
61723               }
61724
61725               classes.push('tag-' + surface);
61726             } // If this is a wikidata-tagged item, add a class for that..
61727
61728
61729             var qid = t.wikidata || t['flag:wikidata'] || t['brand:wikidata'] || t['network:wikidata'] || t['operator:wikidata'];
61730
61731             if (qid) {
61732               classes.push('tag-wikidata');
61733             }
61734
61735             return classes.join(' ').trim();
61736           };
61737
61738           tagClasses.tags = function (val) {
61739             if (!arguments.length) return _tags;
61740             _tags = val;
61741             return tagClasses;
61742           };
61743
61744           return tagClasses;
61745         }
61746
61747         // Patterns only work in Firefox when set directly on element.
61748         // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
61749         var patterns = {
61750           // tag - pattern name
61751           // -or-
61752           // tag - value - pattern name
61753           // -or-
61754           // tag - value - rules (optional tag-values, pattern name)
61755           // (matches earlier rules first, so fallback should be last entry)
61756           amenity: {
61757             grave_yard: 'cemetery',
61758             fountain: 'water_standing'
61759           },
61760           landuse: {
61761             cemetery: [{
61762               religion: 'christian',
61763               pattern: 'cemetery_christian'
61764             }, {
61765               religion: 'buddhist',
61766               pattern: 'cemetery_buddhist'
61767             }, {
61768               religion: 'muslim',
61769               pattern: 'cemetery_muslim'
61770             }, {
61771               religion: 'jewish',
61772               pattern: 'cemetery_jewish'
61773             }, {
61774               pattern: 'cemetery'
61775             }],
61776             construction: 'construction',
61777             farmland: 'farmland',
61778             farmyard: 'farmyard',
61779             forest: [{
61780               leaf_type: 'broadleaved',
61781               pattern: 'forest_broadleaved'
61782             }, {
61783               leaf_type: 'needleleaved',
61784               pattern: 'forest_needleleaved'
61785             }, {
61786               leaf_type: 'leafless',
61787               pattern: 'forest_leafless'
61788             }, {
61789               pattern: 'forest'
61790             } // same as 'leaf_type:mixed'
61791             ],
61792             grave_yard: 'cemetery',
61793             grass: [{
61794               golf: 'green',
61795               pattern: 'golf_green'
61796             }, {
61797               pattern: 'grass'
61798             }],
61799             landfill: 'landfill',
61800             meadow: 'meadow',
61801             military: 'construction',
61802             orchard: 'orchard',
61803             quarry: 'quarry',
61804             vineyard: 'vineyard'
61805           },
61806           natural: {
61807             beach: 'beach',
61808             grassland: 'grass',
61809             sand: 'beach',
61810             scrub: 'scrub',
61811             water: [{
61812               water: 'pond',
61813               pattern: 'pond'
61814             }, {
61815               water: 'reservoir',
61816               pattern: 'water_standing'
61817             }, {
61818               pattern: 'waves'
61819             }],
61820             wetland: [{
61821               wetland: 'marsh',
61822               pattern: 'wetland_marsh'
61823             }, {
61824               wetland: 'swamp',
61825               pattern: 'wetland_swamp'
61826             }, {
61827               wetland: 'bog',
61828               pattern: 'wetland_bog'
61829             }, {
61830               wetland: 'reedbed',
61831               pattern: 'wetland_reedbed'
61832             }, {
61833               pattern: 'wetland'
61834             }],
61835             wood: [{
61836               leaf_type: 'broadleaved',
61837               pattern: 'forest_broadleaved'
61838             }, {
61839               leaf_type: 'needleleaved',
61840               pattern: 'forest_needleleaved'
61841             }, {
61842               leaf_type: 'leafless',
61843               pattern: 'forest_leafless'
61844             }, {
61845               pattern: 'forest'
61846             } // same as 'leaf_type:mixed'
61847             ]
61848           },
61849           traffic_calming: {
61850             island: [{
61851               surface: 'grass',
61852               pattern: 'grass'
61853             }],
61854             chicane: [{
61855               surface: 'grass',
61856               pattern: 'grass'
61857             }],
61858             choker: [{
61859               surface: 'grass',
61860               pattern: 'grass'
61861             }]
61862           }
61863         };
61864         function svgTagPattern(tags) {
61865           // Skip pattern filling if this is a building (buildings don't get patterns applied)
61866           if (tags.building && tags.building !== 'no') {
61867             return null;
61868           }
61869
61870           for (var tag in patterns) {
61871             var entityValue = tags[tag];
61872             if (!entityValue) continue;
61873
61874             if (typeof patterns[tag] === 'string') {
61875               // extra short syntax (just tag) - pattern name
61876               return 'pattern-' + patterns[tag];
61877             } else {
61878               var values = patterns[tag];
61879
61880               for (var value in values) {
61881                 if (entityValue !== value) continue;
61882                 var rules = values[value];
61883
61884                 if (typeof rules === 'string') {
61885                   // short syntax - pattern name
61886                   return 'pattern-' + rules;
61887                 } // long syntax - rule array
61888
61889
61890                 for (var ruleKey in rules) {
61891                   var rule = rules[ruleKey];
61892                   var pass = true;
61893
61894                   for (var criterion in rule) {
61895                     if (criterion !== 'pattern') {
61896                       // reserved for pattern name
61897                       // The only rule is a required tag-value pair
61898                       var v = tags[criterion];
61899
61900                       if (!v || v !== rule[criterion]) {
61901                         pass = false;
61902                         break;
61903                       }
61904                     }
61905                   }
61906
61907                   if (pass) {
61908                     return 'pattern-' + rule.pattern;
61909                   }
61910                 }
61911               }
61912             }
61913           }
61914
61915           return null;
61916         }
61917
61918         function svgAreas(projection, context) {
61919           function getPatternStyle(tags) {
61920             var imageID = svgTagPattern(tags);
61921
61922             if (imageID) {
61923               return 'url("#ideditor-' + imageID + '")';
61924             }
61925
61926             return '';
61927           }
61928
61929           function drawTargets(selection, graph, entities, filter) {
61930             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
61931             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
61932             var getPath = svgPath(projection).geojson;
61933             var activeID = context.activeID();
61934             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
61935
61936             var data = {
61937               targets: [],
61938               nopes: []
61939             };
61940             entities.forEach(function (way) {
61941               var features = svgSegmentWay(way, graph, activeID);
61942               data.targets.push.apply(data.targets, features.passive);
61943               data.nopes.push.apply(data.nopes, features.active);
61944             }); // Targets allow hover and vertex snapping
61945
61946             var targetData = data.targets.filter(getPath);
61947             var targets = selection.selectAll('.area.target-allowed').filter(function (d) {
61948               return filter(d.properties.entity);
61949             }).data(targetData, function key(d) {
61950               return d.id;
61951             }); // exit
61952
61953             targets.exit().remove();
61954
61955             var segmentWasEdited = function segmentWasEdited(d) {
61956               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
61957
61958               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
61959                 return false;
61960               }
61961
61962               return d.properties.nodes.some(function (n) {
61963                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
61964               });
61965             }; // enter/update
61966
61967
61968             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
61969               return 'way area target target-allowed ' + targetClass + d.id;
61970             }).classed('segment-edited', segmentWasEdited); // NOPE
61971
61972             var nopeData = data.nopes.filter(getPath);
61973             var nopes = selection.selectAll('.area.target-nope').filter(function (d) {
61974               return filter(d.properties.entity);
61975             }).data(nopeData, function key(d) {
61976               return d.id;
61977             }); // exit
61978
61979             nopes.exit().remove(); // enter/update
61980
61981             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
61982               return 'way area target target-nope ' + nopeClass + d.id;
61983             }).classed('segment-edited', segmentWasEdited);
61984           }
61985
61986           function drawAreas(selection, graph, entities, filter) {
61987             var path = svgPath(projection, graph, true);
61988             var areas = {};
61989             var multipolygon;
61990             var base = context.history().base();
61991
61992             for (var i = 0; i < entities.length; i++) {
61993               var entity = entities[i];
61994               if (entity.geometry(graph) !== 'area') continue;
61995               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
61996
61997               if (multipolygon) {
61998                 areas[multipolygon.id] = {
61999                   entity: multipolygon.mergeTags(entity.tags),
62000                   area: Math.abs(entity.area(graph))
62001                 };
62002               } else if (!areas[entity.id]) {
62003                 areas[entity.id] = {
62004                   entity: entity,
62005                   area: Math.abs(entity.area(graph))
62006                 };
62007               }
62008             }
62009
62010             var fills = Object.values(areas).filter(function hasPath(a) {
62011               return path(a.entity);
62012             });
62013             fills.sort(function areaSort(a, b) {
62014               return b.area - a.area;
62015             });
62016             fills = fills.map(function (a) {
62017               return a.entity;
62018             });
62019             var strokes = fills.filter(function (area) {
62020               return area.type === 'way';
62021             });
62022             var data = {
62023               clip: fills,
62024               shadow: strokes,
62025               stroke: strokes,
62026               fill: fills
62027             };
62028             var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath-osm').filter(filter).data(data.clip, osmEntity.key);
62029             clipPaths.exit().remove();
62030             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-osm').attr('id', function (entity) {
62031               return 'ideditor-' + entity.id + '-clippath';
62032             });
62033             clipPathsEnter.append('path');
62034             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', path);
62035             var drawLayer = selection.selectAll('.layer-osm.areas');
62036             var touchLayer = selection.selectAll('.layer-touch.areas'); // Draw areas..
62037
62038             var areagroup = drawLayer.selectAll('g.areagroup').data(['fill', 'shadow', 'stroke']);
62039             areagroup = areagroup.enter().append('g').attr('class', function (d) {
62040               return 'areagroup area-' + d;
62041             }).merge(areagroup);
62042             var paths = areagroup.selectAll('path').filter(filter).data(function (layer) {
62043               return data[layer];
62044             }, osmEntity.key);
62045             paths.exit().remove();
62046             var fillpaths = selection.selectAll('.area-fill path.area').nodes();
62047             var bisect = d3_bisector(function (node) {
62048               return -node.__data__.area(graph);
62049             }).left;
62050
62051             function sortedByArea(entity) {
62052               if (this._parent.__data__ === 'fill') {
62053                 return fillpaths[bisect(fillpaths, -entity.area(graph))];
62054               }
62055             }
62056
62057             paths = paths.enter().insert('path', sortedByArea).merge(paths).each(function (entity) {
62058               var layer = this.parentNode.__data__;
62059               this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
62060
62061               if (layer === 'fill') {
62062                 this.setAttribute('clip-path', 'url(#ideditor-' + entity.id + '-clippath)');
62063                 this.style.fill = this.style.stroke = getPatternStyle(entity.tags);
62064               }
62065             }).classed('added', function (d) {
62066               return !base.entities[d.id];
62067             }).classed('geometry-edited', function (d) {
62068               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
62069             }).classed('retagged', function (d) {
62070               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
62071             }).call(svgTagClasses()).attr('d', path); // Draw touch targets..
62072
62073             touchLayer.call(drawTargets, graph, data.stroke, filter);
62074           }
62075
62076           return drawAreas;
62077         }
62078
62079         var fastJsonStableStringify = function fastJsonStableStringify(data, opts) {
62080           if (!opts) opts = {};
62081           if (typeof opts === 'function') opts = {
62082             cmp: opts
62083           };
62084           var cycles = typeof opts.cycles === 'boolean' ? opts.cycles : false;
62085
62086           var cmp = opts.cmp && function (f) {
62087             return function (node) {
62088               return function (a, b) {
62089                 var aobj = {
62090                   key: a,
62091                   value: node[a]
62092                 };
62093                 var bobj = {
62094                   key: b,
62095                   value: node[b]
62096                 };
62097                 return f(aobj, bobj);
62098               };
62099             };
62100           }(opts.cmp);
62101
62102           var seen = [];
62103           return function stringify(node) {
62104             if (node && node.toJSON && typeof node.toJSON === 'function') {
62105               node = node.toJSON();
62106             }
62107
62108             if (node === undefined) return;
62109             if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';
62110             if (_typeof(node) !== 'object') return JSON.stringify(node);
62111             var i, out;
62112
62113             if (Array.isArray(node)) {
62114               out = '[';
62115
62116               for (i = 0; i < node.length; i++) {
62117                 if (i) out += ',';
62118                 out += stringify(node[i]) || 'null';
62119               }
62120
62121               return out + ']';
62122             }
62123
62124             if (node === null) return 'null';
62125
62126             if (seen.indexOf(node) !== -1) {
62127               if (cycles) return JSON.stringify('__cycle__');
62128               throw new TypeError('Converting circular structure to JSON');
62129             }
62130
62131             var seenIndex = seen.push(node) - 1;
62132             var keys = Object.keys(node).sort(cmp && cmp(node));
62133             out = '';
62134
62135             for (i = 0; i < keys.length; i++) {
62136               var key = keys[i];
62137               var value = stringify(node[key]);
62138               if (!value) continue;
62139               if (out) out += ',';
62140               out += JSON.stringify(key) + ':' + value;
62141             }
62142
62143             seen.splice(seenIndex, 1);
62144             return '{' + out + '}';
62145           }(data);
62146         };
62147
62148         //[4]           NameStartChar      ::=          ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
62149         //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
62150         //[5]           Name       ::=          NameStartChar (NameChar)*
62151         var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/; //\u10000-\uEFFFF
62152
62153         var nameChar = new RegExp("[\\-\\.0-9" + nameStartChar.source.slice(1, -1) + "\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
62154         var tagNamePattern = new RegExp('^' + nameStartChar.source + nameChar.source + '*(?:\:' + nameStartChar.source + nameChar.source + '*)?$'); //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
62155         //var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')
62156         //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
62157         //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
62158
62159         var S_TAG = 0; //tag name offerring
62160
62161         var S_ATTR = 1; //attr name offerring 
62162
62163         var S_ATTR_SPACE = 2; //attr name end and space offer
62164
62165         var S_EQ = 3; //=space?
62166
62167         var S_ATTR_NOQUOT_VALUE = 4; //attr value(no quot value only)
62168
62169         var S_ATTR_END = 5; //attr value end and no space(quot end)
62170
62171         var S_TAG_SPACE = 6; //(attr value end || tag end ) && (space offer)
62172
62173         var S_TAG_CLOSE = 7; //closed el<el />
62174
62175         function XMLReader() {}
62176
62177         XMLReader.prototype = {
62178           parse: function parse(source, defaultNSMap, entityMap) {
62179             var domBuilder = this.domBuilder;
62180             domBuilder.startDocument();
62181
62182             _copy(defaultNSMap, defaultNSMap = {});
62183
62184             _parse(source, defaultNSMap, entityMap, domBuilder, this.errorHandler);
62185
62186             domBuilder.endDocument();
62187           }
62188         };
62189
62190         function _parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
62191           function fixedFromCharCode(code) {
62192             // String.prototype.fromCharCode does not supports
62193             // > 2 bytes unicode chars directly
62194             if (code > 0xffff) {
62195               code -= 0x10000;
62196               var surrogate1 = 0xd800 + (code >> 10),
62197                   surrogate2 = 0xdc00 + (code & 0x3ff);
62198               return String.fromCharCode(surrogate1, surrogate2);
62199             } else {
62200               return String.fromCharCode(code);
62201             }
62202           }
62203
62204           function entityReplacer(a) {
62205             var k = a.slice(1, -1);
62206
62207             if (k in entityMap) {
62208               return entityMap[k];
62209             } else if (k.charAt(0) === '#') {
62210               return fixedFromCharCode(parseInt(k.substr(1).replace('x', '0x')));
62211             } else {
62212               errorHandler.error('entity not found:' + a);
62213               return a;
62214             }
62215           }
62216
62217           function appendText(end) {
62218             //has some bugs
62219             if (end > start) {
62220               var xt = source.substring(start, end).replace(/&#?\w+;/g, entityReplacer);
62221               locator && position(start);
62222               domBuilder.characters(xt, 0, end - start);
62223               start = end;
62224             }
62225           }
62226
62227           function position(p, m) {
62228             while (p >= lineEnd && (m = linePattern.exec(source))) {
62229               lineStart = m.index;
62230               lineEnd = lineStart + m[0].length;
62231               locator.lineNumber++; //console.log('line++:',locator,startPos,endPos)
62232             }
62233
62234             locator.columnNumber = p - lineStart + 1;
62235           }
62236
62237           var lineStart = 0;
62238           var lineEnd = 0;
62239           var linePattern = /.*(?:\r\n?|\n)|.*$/g;
62240           var locator = domBuilder.locator;
62241           var parseStack = [{
62242             currentNSMap: defaultNSMapCopy
62243           }];
62244           var closeMap = {};
62245           var start = 0;
62246
62247           while (true) {
62248             try {
62249               var tagStart = source.indexOf('<', start);
62250
62251               if (tagStart < 0) {
62252                 if (!source.substr(start).match(/^\s*$/)) {
62253                   var doc = domBuilder.doc;
62254                   var text = doc.createTextNode(source.substr(start));
62255                   doc.appendChild(text);
62256                   domBuilder.currentElement = text;
62257                 }
62258
62259                 return;
62260               }
62261
62262               if (tagStart > start) {
62263                 appendText(tagStart);
62264               }
62265
62266               switch (source.charAt(tagStart + 1)) {
62267                 case '/':
62268                   var end = source.indexOf('>', tagStart + 3);
62269                   var tagName = source.substring(tagStart + 2, end);
62270                   var config = parseStack.pop();
62271
62272                   if (end < 0) {
62273                     tagName = source.substring(tagStart + 2).replace(/[\s<].*/, ''); //console.error('#@@@@@@'+tagName)
62274
62275                     errorHandler.error("end tag name: " + tagName + ' is not complete:' + config.tagName);
62276                     end = tagStart + 1 + tagName.length;
62277                   } else if (tagName.match(/\s</)) {
62278                     tagName = tagName.replace(/[\s<].*/, '');
62279                     errorHandler.error("end tag name: " + tagName + ' maybe not complete');
62280                     end = tagStart + 1 + tagName.length;
62281                   } //console.error(parseStack.length,parseStack)
62282                   //console.error(config);
62283
62284
62285                   var localNSMap = config.localNSMap;
62286                   var endMatch = config.tagName == tagName;
62287                   var endIgnoreCaseMach = endMatch || config.tagName && config.tagName.toLowerCase() == tagName.toLowerCase();
62288
62289                   if (endIgnoreCaseMach) {
62290                     domBuilder.endElement(config.uri, config.localName, tagName);
62291
62292                     if (localNSMap) {
62293                       for (var prefix in localNSMap) {
62294                         domBuilder.endPrefixMapping(prefix);
62295                       }
62296                     }
62297
62298                     if (!endMatch) {
62299                       errorHandler.fatalError("end tag name: " + tagName + ' is not match the current start tagName:' + config.tagName);
62300                     }
62301                   } else {
62302                     parseStack.push(config);
62303                   }
62304
62305                   end++;
62306                   break;
62307                 // end elment
62308
62309                 case '?':
62310                   // <?...?>
62311                   locator && position(tagStart);
62312                   end = parseInstruction(source, tagStart, domBuilder);
62313                   break;
62314
62315                 case '!':
62316                   // <!doctype,<![CDATA,<!--
62317                   locator && position(tagStart);
62318                   end = parseDCC(source, tagStart, domBuilder, errorHandler);
62319                   break;
62320
62321                 default:
62322                   locator && position(tagStart);
62323                   var el = new ElementAttributes();
62324                   var currentNSMap = parseStack[parseStack.length - 1].currentNSMap; //elStartEnd
62325
62326                   var end = parseElementStartPart(source, tagStart, el, currentNSMap, entityReplacer, errorHandler);
62327                   var len = el.length;
62328
62329                   if (!el.closed && fixSelfClosed(source, end, el.tagName, closeMap)) {
62330                     el.closed = true;
62331
62332                     if (!entityMap.nbsp) {
62333                       errorHandler.warning('unclosed xml attribute');
62334                     }
62335                   }
62336
62337                   if (locator && len) {
62338                     var locator2 = copyLocator(locator, {}); //try{//attribute position fixed
62339
62340                     for (var i = 0; i < len; i++) {
62341                       var a = el[i];
62342                       position(a.offset);
62343                       a.locator = copyLocator(locator, {});
62344                     } //}catch(e){console.error('@@@@@'+e)}
62345
62346
62347                     domBuilder.locator = locator2;
62348
62349                     if (appendElement(el, domBuilder, currentNSMap)) {
62350                       parseStack.push(el);
62351                     }
62352
62353                     domBuilder.locator = locator;
62354                   } else {
62355                     if (appendElement(el, domBuilder, currentNSMap)) {
62356                       parseStack.push(el);
62357                     }
62358                   }
62359
62360                   if (el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed) {
62361                     end = parseHtmlSpecialContent(source, end, el.tagName, entityReplacer, domBuilder);
62362                   } else {
62363                     end++;
62364                   }
62365
62366               }
62367             } catch (e) {
62368               errorHandler.error('element parse error: ' + e); //errorHandler.error('element parse error: '+e);
62369
62370               end = -1; //throw e;
62371             }
62372
62373             if (end > start) {
62374               start = end;
62375             } else {
62376               //TODO: 这里有可能sax回退,有位置错误风险
62377               appendText(Math.max(tagStart, start) + 1);
62378             }
62379           }
62380         }
62381
62382         function copyLocator(f, t) {
62383           t.lineNumber = f.lineNumber;
62384           t.columnNumber = f.columnNumber;
62385           return t;
62386         }
62387         /**
62388          * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
62389          * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
62390          */
62391
62392
62393         function parseElementStartPart(source, start, el, currentNSMap, entityReplacer, errorHandler) {
62394           var attrName;
62395           var value;
62396           var p = ++start;
62397           var s = S_TAG; //status
62398
62399           while (true) {
62400             var c = source.charAt(p);
62401
62402             switch (c) {
62403               case '=':
62404                 if (s === S_ATTR) {
62405                   //attrName
62406                   attrName = source.slice(start, p);
62407                   s = S_EQ;
62408                 } else if (s === S_ATTR_SPACE) {
62409                   s = S_EQ;
62410                 } else {
62411                   //fatalError: equal must after attrName or space after attrName
62412                   throw new Error('attribute equal must after attrName');
62413                 }
62414
62415                 break;
62416
62417               case '\'':
62418               case '"':
62419                 if (s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
62420                 ) {
62421                     //equal
62422                     if (s === S_ATTR) {
62423                       errorHandler.warning('attribute value must after "="');
62424                       attrName = source.slice(start, p);
62425                     }
62426
62427                     start = p + 1;
62428                     p = source.indexOf(c, start);
62429
62430                     if (p > 0) {
62431                       value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
62432                       el.add(attrName, value, start - 1);
62433                       s = S_ATTR_END;
62434                     } else {
62435                       //fatalError: no end quot match
62436                       throw new Error('attribute value no end \'' + c + '\' match');
62437                     }
62438                   } else if (s == S_ATTR_NOQUOT_VALUE) {
62439                   value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer); //console.log(attrName,value,start,p)
62440
62441                   el.add(attrName, value, start); //console.dir(el)
62442
62443                   errorHandler.warning('attribute "' + attrName + '" missed start quot(' + c + ')!!');
62444                   start = p + 1;
62445                   s = S_ATTR_END;
62446                 } else {
62447                   //fatalError: no equal before
62448                   throw new Error('attribute value must after "="');
62449                 }
62450
62451                 break;
62452
62453               case '/':
62454                 switch (s) {
62455                   case S_TAG:
62456                     el.setTagName(source.slice(start, p));
62457
62458                   case S_ATTR_END:
62459                   case S_TAG_SPACE:
62460                   case S_TAG_CLOSE:
62461                     s = S_TAG_CLOSE;
62462                     el.closed = true;
62463
62464                   case S_ATTR_NOQUOT_VALUE:
62465                   case S_ATTR:
62466                   case S_ATTR_SPACE:
62467                     break;
62468                   //case S_EQ:
62469
62470                   default:
62471                     throw new Error("attribute invalid close char('/')");
62472                 }
62473
62474                 break;
62475
62476               case '':
62477                 //end document
62478                 //throw new Error('unexpected end of input')
62479                 errorHandler.error('unexpected end of input');
62480
62481                 if (s == S_TAG) {
62482                   el.setTagName(source.slice(start, p));
62483                 }
62484
62485                 return p;
62486
62487               case '>':
62488                 switch (s) {
62489                   case S_TAG:
62490                     el.setTagName(source.slice(start, p));
62491
62492                   case S_ATTR_END:
62493                   case S_TAG_SPACE:
62494                   case S_TAG_CLOSE:
62495                     break;
62496                   //normal
62497
62498                   case S_ATTR_NOQUOT_VALUE: //Compatible state
62499
62500                   case S_ATTR:
62501                     value = source.slice(start, p);
62502
62503                     if (value.slice(-1) === '/') {
62504                       el.closed = true;
62505                       value = value.slice(0, -1);
62506                     }
62507
62508                   case S_ATTR_SPACE:
62509                     if (s === S_ATTR_SPACE) {
62510                       value = attrName;
62511                     }
62512
62513                     if (s == S_ATTR_NOQUOT_VALUE) {
62514                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
62515                       el.add(attrName, value.replace(/&#?\w+;/g, entityReplacer), start);
62516                     } else {
62517                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)) {
62518                         errorHandler.warning('attribute "' + value + '" missed value!! "' + value + '" instead!!');
62519                       }
62520
62521                       el.add(value, value, start);
62522                     }
62523
62524                     break;
62525
62526                   case S_EQ:
62527                     throw new Error('attribute value missed!!');
62528                 } //                    console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
62529
62530
62531                 return p;
62532
62533               /*xml space '\x20' | #x9 | #xD | #xA; */
62534
62535               case "\x80":
62536                 c = ' ';
62537
62538               default:
62539                 if (c <= ' ') {
62540                   //space
62541                   switch (s) {
62542                     case S_TAG:
62543                       el.setTagName(source.slice(start, p)); //tagName
62544
62545                       s = S_TAG_SPACE;
62546                       break;
62547
62548                     case S_ATTR:
62549                       attrName = source.slice(start, p);
62550                       s = S_ATTR_SPACE;
62551                       break;
62552
62553                     case S_ATTR_NOQUOT_VALUE:
62554                       var value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
62555                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
62556                       el.add(attrName, value, start);
62557
62558                     case S_ATTR_END:
62559                       s = S_TAG_SPACE;
62560                       break;
62561                     //case S_TAG_SPACE:
62562                     //case S_EQ:
62563                     //case S_ATTR_SPACE:
62564                     //  void();break;
62565                     //case S_TAG_CLOSE:
62566                     //ignore warning
62567                   }
62568                 } else {
62569                   //not space
62570                   //S_TAG,      S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
62571                   //S_ATTR_SPACE,       S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
62572                   switch (s) {
62573                     //case S_TAG:void();break;
62574                     //case S_ATTR:void();break;
62575                     //case S_ATTR_NOQUOT_VALUE:void();break;
62576                     case S_ATTR_SPACE:
62577                       el.tagName;
62578
62579                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)) {
62580                         errorHandler.warning('attribute "' + attrName + '" missed value!! "' + attrName + '" instead2!!');
62581                       }
62582
62583                       el.add(attrName, attrName, start);
62584                       start = p;
62585                       s = S_ATTR;
62586                       break;
62587
62588                     case S_ATTR_END:
62589                       errorHandler.warning('attribute space is required"' + attrName + '"!!');
62590
62591                     case S_TAG_SPACE:
62592                       s = S_ATTR;
62593                       start = p;
62594                       break;
62595
62596                     case S_EQ:
62597                       s = S_ATTR_NOQUOT_VALUE;
62598                       start = p;
62599                       break;
62600
62601                     case S_TAG_CLOSE:
62602                       throw new Error("elements closed character '/' and '>' must be connected to");
62603                   }
62604                 }
62605
62606             } //end outer switch
62607             //console.log('p++',p)
62608
62609
62610             p++;
62611           }
62612         }
62613         /**
62614          * @return true if has new namespace define
62615          */
62616
62617
62618         function appendElement(el, domBuilder, currentNSMap) {
62619           var tagName = el.tagName;
62620           var localNSMap = null; //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
62621
62622           var i = el.length;
62623
62624           while (i--) {
62625             var a = el[i];
62626             var qName = a.qName;
62627             var value = a.value;
62628             var nsp = qName.indexOf(':');
62629
62630             if (nsp > 0) {
62631               var prefix = a.prefix = qName.slice(0, nsp);
62632               var localName = qName.slice(nsp + 1);
62633               var nsPrefix = prefix === 'xmlns' && localName;
62634             } else {
62635               localName = qName;
62636               prefix = null;
62637               nsPrefix = qName === 'xmlns' && '';
62638             } //can not set prefix,because prefix !== ''
62639
62640
62641             a.localName = localName; //prefix == null for no ns prefix attribute 
62642
62643             if (nsPrefix !== false) {
62644               //hack!!
62645               if (localNSMap == null) {
62646                 localNSMap = {}; //console.log(currentNSMap,0)
62647
62648                 _copy(currentNSMap, currentNSMap = {}); //console.log(currentNSMap,1)
62649
62650               }
62651
62652               currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
62653               a.uri = 'http://www.w3.org/2000/xmlns/';
62654               domBuilder.startPrefixMapping(nsPrefix, value);
62655             }
62656           }
62657
62658           var i = el.length;
62659
62660           while (i--) {
62661             a = el[i];
62662             var prefix = a.prefix;
62663
62664             if (prefix) {
62665               //no prefix attribute has no namespace
62666               if (prefix === 'xml') {
62667                 a.uri = 'http://www.w3.org/XML/1998/namespace';
62668               }
62669
62670               if (prefix !== 'xmlns') {
62671                 a.uri = currentNSMap[prefix || '']; //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
62672               }
62673             }
62674           }
62675
62676           var nsp = tagName.indexOf(':');
62677
62678           if (nsp > 0) {
62679             prefix = el.prefix = tagName.slice(0, nsp);
62680             localName = el.localName = tagName.slice(nsp + 1);
62681           } else {
62682             prefix = null; //important!!
62683
62684             localName = el.localName = tagName;
62685           } //no prefix element has default namespace
62686
62687
62688           var ns = el.uri = currentNSMap[prefix || ''];
62689           domBuilder.startElement(ns, localName, tagName, el); //endPrefixMapping and startPrefixMapping have not any help for dom builder
62690           //localNSMap = null
62691
62692           if (el.closed) {
62693             domBuilder.endElement(ns, localName, tagName);
62694
62695             if (localNSMap) {
62696               for (prefix in localNSMap) {
62697                 domBuilder.endPrefixMapping(prefix);
62698               }
62699             }
62700           } else {
62701             el.currentNSMap = currentNSMap;
62702             el.localNSMap = localNSMap; //parseStack.push(el);
62703
62704             return true;
62705           }
62706         }
62707
62708         function parseHtmlSpecialContent(source, elStartEnd, tagName, entityReplacer, domBuilder) {
62709           if (/^(?:script|textarea)$/i.test(tagName)) {
62710             var elEndStart = source.indexOf('</' + tagName + '>', elStartEnd);
62711             var text = source.substring(elStartEnd + 1, elEndStart);
62712
62713             if (/[&<]/.test(text)) {
62714               if (/^script$/i.test(tagName)) {
62715                 //if(!/\]\]>/.test(text)){
62716                 //lexHandler.startCDATA();
62717                 domBuilder.characters(text, 0, text.length); //lexHandler.endCDATA();
62718
62719                 return elEndStart; //}
62720               } //}else{//text area
62721
62722
62723               text = text.replace(/&#?\w+;/g, entityReplacer);
62724               domBuilder.characters(text, 0, text.length);
62725               return elEndStart; //}
62726             }
62727           }
62728
62729           return elStartEnd + 1;
62730         }
62731
62732         function fixSelfClosed(source, elStartEnd, tagName, closeMap) {
62733           //if(tagName in closeMap){
62734           var pos = closeMap[tagName];
62735
62736           if (pos == null) {
62737             //console.log(tagName)
62738             pos = source.lastIndexOf('</' + tagName + '>');
62739
62740             if (pos < elStartEnd) {
62741               //忘记闭合
62742               pos = source.lastIndexOf('</' + tagName);
62743             }
62744
62745             closeMap[tagName] = pos;
62746           }
62747
62748           return pos < elStartEnd; //} 
62749         }
62750
62751         function _copy(source, target) {
62752           for (var n in source) {
62753             target[n] = source[n];
62754           }
62755         }
62756
62757         function parseDCC(source, start, domBuilder, errorHandler) {
62758           //sure start with '<!'
62759           var next = source.charAt(start + 2);
62760
62761           switch (next) {
62762             case '-':
62763               if (source.charAt(start + 3) === '-') {
62764                 var end = source.indexOf('-->', start + 4); //append comment source.substring(4,end)//<!--
62765
62766                 if (end > start) {
62767                   domBuilder.comment(source, start + 4, end - start - 4);
62768                   return end + 3;
62769                 } else {
62770                   errorHandler.error("Unclosed comment");
62771                   return -1;
62772                 }
62773               } else {
62774                 //error
62775                 return -1;
62776               }
62777
62778             default:
62779               if (source.substr(start + 3, 6) == 'CDATA[') {
62780                 var end = source.indexOf(']]>', start + 9);
62781                 domBuilder.startCDATA();
62782                 domBuilder.characters(source, start + 9, end - start - 9);
62783                 domBuilder.endCDATA();
62784                 return end + 3;
62785               } //<!DOCTYPE
62786               //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
62787
62788
62789               var matchs = split(source, start);
62790               var len = matchs.length;
62791
62792               if (len > 1 && /!doctype/i.test(matchs[0][0])) {
62793                 var name = matchs[1][0];
62794                 var pubid = len > 3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
62795                 var sysid = len > 4 && matchs[4][0];
62796                 var lastMatch = matchs[len - 1];
62797                 domBuilder.startDTD(name, pubid && pubid.replace(/^(['"])(.*?)\1$/, '$2'), sysid && sysid.replace(/^(['"])(.*?)\1$/, '$2'));
62798                 domBuilder.endDTD();
62799                 return lastMatch.index + lastMatch[0].length;
62800               }
62801
62802           }
62803
62804           return -1;
62805         }
62806
62807         function parseInstruction(source, start, domBuilder) {
62808           var end = source.indexOf('?>', start);
62809
62810           if (end) {
62811             var match = source.substring(start, end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
62812
62813             if (match) {
62814               match[0].length;
62815               domBuilder.processingInstruction(match[1], match[2]);
62816               return end + 2;
62817             } else {
62818               //error
62819               return -1;
62820             }
62821           }
62822
62823           return -1;
62824         }
62825         /**
62826          * @param source
62827          */
62828
62829
62830         function ElementAttributes(source) {}
62831
62832         ElementAttributes.prototype = {
62833           setTagName: function setTagName(tagName) {
62834             if (!tagNamePattern.test(tagName)) {
62835               throw new Error('invalid tagName:' + tagName);
62836             }
62837
62838             this.tagName = tagName;
62839           },
62840           add: function add(qName, value, offset) {
62841             if (!tagNamePattern.test(qName)) {
62842               throw new Error('invalid attribute:' + qName);
62843             }
62844
62845             this[this.length++] = {
62846               qName: qName,
62847               value: value,
62848               offset: offset
62849             };
62850           },
62851           length: 0,
62852           getLocalName: function getLocalName(i) {
62853             return this[i].localName;
62854           },
62855           getLocator: function getLocator(i) {
62856             return this[i].locator;
62857           },
62858           getQName: function getQName(i) {
62859             return this[i].qName;
62860           },
62861           getURI: function getURI(i) {
62862             return this[i].uri;
62863           },
62864           getValue: function getValue(i) {
62865             return this[i].value;
62866           } //  ,getIndex:function(uri, localName)){
62867           //            if(localName){
62868           //                    
62869           //            }else{
62870           //                    var qName = uri
62871           //            }
62872           //    },
62873           //    getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
62874           //    getType:function(uri,localName){}
62875           //    getType:function(i){},
62876
62877         };
62878
62879         function _set_proto_(thiz, parent) {
62880           thiz.__proto__ = parent;
62881           return thiz;
62882         }
62883
62884         if (!(_set_proto_({}, _set_proto_.prototype) instanceof _set_proto_)) {
62885           _set_proto_ = function _set_proto_(thiz, parent) {
62886             function p() {}
62887             p.prototype = parent;
62888             p = new p();
62889
62890             for (parent in thiz) {
62891               p[parent] = thiz[parent];
62892             }
62893
62894             return p;
62895           };
62896         }
62897
62898         function split(source, start) {
62899           var match;
62900           var buf = [];
62901           var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
62902           reg.lastIndex = start;
62903           reg.exec(source); //skip <
62904
62905           while (match = reg.exec(source)) {
62906             buf.push(match);
62907             if (match[1]) return buf;
62908           }
62909         }
62910
62911         var XMLReader_1 = XMLReader;
62912         var sax = {
62913           XMLReader: XMLReader_1
62914         };
62915
62916         /*
62917          * DOM Level 2
62918          * Object DOMException
62919          * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
62920          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
62921          */
62922         function copy(src, dest) {
62923           for (var p in src) {
62924             dest[p] = src[p];
62925           }
62926         }
62927         /**
62928         ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
62929         ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
62930          */
62931
62932
62933         function _extends(Class, Super) {
62934           var pt = Class.prototype;
62935
62936           if (Object.create) {
62937             var ppt = Object.create(Super.prototype);
62938             pt.__proto__ = ppt;
62939           }
62940
62941           if (!(pt instanceof Super)) {
62942             var t = function t() {};
62943             t.prototype = Super.prototype;
62944             t = new t();
62945             copy(pt, t);
62946             Class.prototype = pt = t;
62947           }
62948
62949           if (pt.constructor != Class) {
62950             if (typeof Class != 'function') {
62951               console.error("unknow Class:" + Class);
62952             }
62953
62954             pt.constructor = Class;
62955           }
62956         }
62957
62958         var htmlns = 'http://www.w3.org/1999/xhtml'; // Node Types
62959
62960         var NodeType = {};
62961         var ELEMENT_NODE = NodeType.ELEMENT_NODE = 1;
62962         var ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2;
62963         var TEXT_NODE = NodeType.TEXT_NODE = 3;
62964         var CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4;
62965         var ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5;
62966         var ENTITY_NODE = NodeType.ENTITY_NODE = 6;
62967         var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
62968         var COMMENT_NODE = NodeType.COMMENT_NODE = 8;
62969         var DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9;
62970         var DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10;
62971         var DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11;
62972         var NOTATION_NODE = NodeType.NOTATION_NODE = 12; // ExceptionCode
62973
62974         var ExceptionCode = {};
62975         var ExceptionMessage = {};
62976         ExceptionCode.INDEX_SIZE_ERR = (ExceptionMessage[1] = "Index size error", 1);
62977         ExceptionCode.DOMSTRING_SIZE_ERR = (ExceptionMessage[2] = "DOMString size error", 2);
62978         var HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR = (ExceptionMessage[3] = "Hierarchy request error", 3);
62979         ExceptionCode.WRONG_DOCUMENT_ERR = (ExceptionMessage[4] = "Wrong document", 4);
62980         ExceptionCode.INVALID_CHARACTER_ERR = (ExceptionMessage[5] = "Invalid character", 5);
62981         ExceptionCode.NO_DATA_ALLOWED_ERR = (ExceptionMessage[6] = "No data allowed", 6);
62982         ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = (ExceptionMessage[7] = "No modification allowed", 7);
62983         var NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR = (ExceptionMessage[8] = "Not found", 8);
62984         ExceptionCode.NOT_SUPPORTED_ERR = (ExceptionMessage[9] = "Not supported", 9);
62985         var INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR = (ExceptionMessage[10] = "Attribute in use", 10); //level2
62986
62987         ExceptionCode.INVALID_STATE_ERR = (ExceptionMessage[11] = "Invalid state", 11);
62988         ExceptionCode.SYNTAX_ERR = (ExceptionMessage[12] = "Syntax error", 12);
62989         ExceptionCode.INVALID_MODIFICATION_ERR = (ExceptionMessage[13] = "Invalid modification", 13);
62990         ExceptionCode.NAMESPACE_ERR = (ExceptionMessage[14] = "Invalid namespace", 14);
62991         ExceptionCode.INVALID_ACCESS_ERR = (ExceptionMessage[15] = "Invalid access", 15);
62992
62993         function DOMException$1(code, message) {
62994           if (message instanceof Error) {
62995             var error = message;
62996           } else {
62997             error = this;
62998             Error.call(this, ExceptionMessage[code]);
62999             this.message = ExceptionMessage[code];
63000             if (Error.captureStackTrace) Error.captureStackTrace(this, DOMException$1);
63001           }
63002
63003           error.code = code;
63004           if (message) this.message = this.message + ": " + message;
63005           return error;
63006         }
63007         DOMException$1.prototype = Error.prototype;
63008         copy(ExceptionCode, DOMException$1);
63009         /**
63010          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
63011          * The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live.
63012          * The items in the NodeList are accessible via an integral index, starting from 0.
63013          */
63014
63015         function NodeList() {}
63016         NodeList.prototype = {
63017           /**
63018            * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
63019            * @standard level1
63020            */
63021           length: 0,
63022
63023           /**
63024            * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null.
63025            * @standard level1
63026            * @param index  unsigned long 
63027            *   Index into the collection.
63028            * @return Node
63029            *    The node at the indexth position in the NodeList, or null if that is not a valid index. 
63030            */
63031           item: function item(index) {
63032             return this[index] || null;
63033           },
63034           toString: function toString(isHTML, nodeFilter) {
63035             for (var buf = [], i = 0; i < this.length; i++) {
63036               serializeToString(this[i], buf, isHTML, nodeFilter);
63037             }
63038
63039             return buf.join('');
63040           }
63041         };
63042
63043         function LiveNodeList(node, refresh) {
63044           this._node = node;
63045           this._refresh = refresh;
63046
63047           _updateLiveList(this);
63048         }
63049
63050         function _updateLiveList(list) {
63051           var inc = list._node._inc || list._node.ownerDocument._inc;
63052
63053           if (list._inc != inc) {
63054             var ls = list._refresh(list._node); //console.log(ls.length)
63055
63056
63057             __set__(list, 'length', ls.length);
63058
63059             copy(ls, list);
63060             list._inc = inc;
63061           }
63062         }
63063
63064         LiveNodeList.prototype.item = function (i) {
63065           _updateLiveList(this);
63066
63067           return this[i];
63068         };
63069
63070         _extends(LiveNodeList, NodeList);
63071         /**
63072          * 
63073          * Objects implementing the NamedNodeMap interface are used to represent collections of nodes that can be accessed by name. Note that NamedNodeMap does not inherit from NodeList; NamedNodeMaps are not maintained in any particular order. Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal index, but this is simply to allow convenient enumeration of the contents of a NamedNodeMap, and does not imply that the DOM specifies an order to these Nodes.
63074          * NamedNodeMap objects in the DOM are live.
63075          * used for attributes or DocumentType entities 
63076          */
63077
63078
63079         function NamedNodeMap() {}
63080
63081         function _findNodeIndex(list, node) {
63082           var i = list.length;
63083
63084           while (i--) {
63085             if (list[i] === node) {
63086               return i;
63087             }
63088           }
63089         }
63090
63091         function _addNamedNode(el, list, newAttr, oldAttr) {
63092           if (oldAttr) {
63093             list[_findNodeIndex(list, oldAttr)] = newAttr;
63094           } else {
63095             list[list.length++] = newAttr;
63096           }
63097
63098           if (el) {
63099             newAttr.ownerElement = el;
63100             var doc = el.ownerDocument;
63101
63102             if (doc) {
63103               oldAttr && _onRemoveAttribute(doc, el, oldAttr);
63104
63105               _onAddAttribute(doc, el, newAttr);
63106             }
63107           }
63108         }
63109
63110         function _removeNamedNode(el, list, attr) {
63111           //console.log('remove attr:'+attr)
63112           var i = _findNodeIndex(list, attr);
63113
63114           if (i >= 0) {
63115             var lastIndex = list.length - 1;
63116
63117             while (i < lastIndex) {
63118               list[i] = list[++i];
63119             }
63120
63121             list.length = lastIndex;
63122
63123             if (el) {
63124               var doc = el.ownerDocument;
63125
63126               if (doc) {
63127                 _onRemoveAttribute(doc, el, attr);
63128
63129                 attr.ownerElement = null;
63130               }
63131             }
63132           } else {
63133             throw DOMException$1(NOT_FOUND_ERR, new Error(el.tagName + '@' + attr));
63134           }
63135         }
63136
63137         NamedNodeMap.prototype = {
63138           length: 0,
63139           item: NodeList.prototype.item,
63140           getNamedItem: function getNamedItem(key) {
63141             //          if(key.indexOf(':')>0 || key == 'xmlns'){
63142             //                  return null;
63143             //          }
63144             //console.log()
63145             var i = this.length;
63146
63147             while (i--) {
63148               var attr = this[i]; //console.log(attr.nodeName,key)
63149
63150               if (attr.nodeName == key) {
63151                 return attr;
63152               }
63153             }
63154           },
63155           setNamedItem: function setNamedItem(attr) {
63156             var el = attr.ownerElement;
63157
63158             if (el && el != this._ownerElement) {
63159               throw new DOMException$1(INUSE_ATTRIBUTE_ERR);
63160             }
63161
63162             var oldAttr = this.getNamedItem(attr.nodeName);
63163
63164             _addNamedNode(this._ownerElement, this, attr, oldAttr);
63165
63166             return oldAttr;
63167           },
63168
63169           /* returns Node */
63170           setNamedItemNS: function setNamedItemNS(attr) {
63171             // raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
63172             var el = attr.ownerElement,
63173                 oldAttr;
63174
63175             if (el && el != this._ownerElement) {
63176               throw new DOMException$1(INUSE_ATTRIBUTE_ERR);
63177             }
63178
63179             oldAttr = this.getNamedItemNS(attr.namespaceURI, attr.localName);
63180
63181             _addNamedNode(this._ownerElement, this, attr, oldAttr);
63182
63183             return oldAttr;
63184           },
63185
63186           /* returns Node */
63187           removeNamedItem: function removeNamedItem(key) {
63188             var attr = this.getNamedItem(key);
63189
63190             _removeNamedNode(this._ownerElement, this, attr);
63191
63192             return attr;
63193           },
63194           // raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
63195           //for level2
63196           removeNamedItemNS: function removeNamedItemNS(namespaceURI, localName) {
63197             var attr = this.getNamedItemNS(namespaceURI, localName);
63198
63199             _removeNamedNode(this._ownerElement, this, attr);
63200
63201             return attr;
63202           },
63203           getNamedItemNS: function getNamedItemNS(namespaceURI, localName) {
63204             var i = this.length;
63205
63206             while (i--) {
63207               var node = this[i];
63208
63209               if (node.localName == localName && node.namespaceURI == namespaceURI) {
63210                 return node;
63211               }
63212             }
63213
63214             return null;
63215           }
63216         };
63217         /**
63218          * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
63219          */
63220
63221         function DOMImplementation(
63222         /* Object */
63223         features) {
63224           this._features = {};
63225
63226           if (features) {
63227             for (var feature in features) {
63228               this._features = features[feature];
63229             }
63230           }
63231         }
63232         DOMImplementation.prototype = {
63233           hasFeature: function hasFeature(
63234           /* string */
63235           feature,
63236           /* string */
63237           version) {
63238             var versions = this._features[feature.toLowerCase()];
63239
63240             if (versions && (!version || version in versions)) {
63241               return true;
63242             } else {
63243               return false;
63244             }
63245           },
63246           // Introduced in DOM Level 2:
63247           createDocument: function createDocument(namespaceURI, qualifiedName, doctype) {
63248             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
63249             var doc = new Document();
63250             doc.implementation = this;
63251             doc.childNodes = new NodeList();
63252             doc.doctype = doctype;
63253
63254             if (doctype) {
63255               doc.appendChild(doctype);
63256             }
63257
63258             if (qualifiedName) {
63259               var root = doc.createElementNS(namespaceURI, qualifiedName);
63260               doc.appendChild(root);
63261             }
63262
63263             return doc;
63264           },
63265           // Introduced in DOM Level 2:
63266           createDocumentType: function createDocumentType(qualifiedName, publicId, systemId) {
63267             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
63268             var node = new DocumentType();
63269             node.name = qualifiedName;
63270             node.nodeName = qualifiedName;
63271             node.publicId = publicId;
63272             node.systemId = systemId; // Introduced in DOM Level 2:
63273             //readonly attribute DOMString        internalSubset;
63274             //TODO:..
63275             //  readonly attribute NamedNodeMap     entities;
63276             //  readonly attribute NamedNodeMap     notations;
63277
63278             return node;
63279           }
63280         };
63281         /**
63282          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
63283          */
63284
63285         function Node() {}
63286         Node.prototype = {
63287           firstChild: null,
63288           lastChild: null,
63289           previousSibling: null,
63290           nextSibling: null,
63291           attributes: null,
63292           parentNode: null,
63293           childNodes: null,
63294           ownerDocument: null,
63295           nodeValue: null,
63296           namespaceURI: null,
63297           prefix: null,
63298           localName: null,
63299           // Modified in DOM Level 2:
63300           insertBefore: function insertBefore(newChild, refChild) {
63301             //raises 
63302             return _insertBefore(this, newChild, refChild);
63303           },
63304           replaceChild: function replaceChild(newChild, oldChild) {
63305             //raises 
63306             this.insertBefore(newChild, oldChild);
63307
63308             if (oldChild) {
63309               this.removeChild(oldChild);
63310             }
63311           },
63312           removeChild: function removeChild(oldChild) {
63313             return _removeChild(this, oldChild);
63314           },
63315           appendChild: function appendChild(newChild) {
63316             return this.insertBefore(newChild, null);
63317           },
63318           hasChildNodes: function hasChildNodes() {
63319             return this.firstChild != null;
63320           },
63321           cloneNode: function cloneNode(deep) {
63322             return _cloneNode(this.ownerDocument || this, this, deep);
63323           },
63324           // Modified in DOM Level 2:
63325           normalize: function normalize() {
63326             var child = this.firstChild;
63327
63328             while (child) {
63329               var next = child.nextSibling;
63330
63331               if (next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE) {
63332                 this.removeChild(next);
63333                 child.appendData(next.data);
63334               } else {
63335                 child.normalize();
63336                 child = next;
63337               }
63338             }
63339           },
63340           // Introduced in DOM Level 2:
63341           isSupported: function isSupported(feature, version) {
63342             return this.ownerDocument.implementation.hasFeature(feature, version);
63343           },
63344           // Introduced in DOM Level 2:
63345           hasAttributes: function hasAttributes() {
63346             return this.attributes.length > 0;
63347           },
63348           lookupPrefix: function lookupPrefix(namespaceURI) {
63349             var el = this;
63350
63351             while (el) {
63352               var map = el._nsMap; //console.dir(map)
63353
63354               if (map) {
63355                 for (var n in map) {
63356                   if (map[n] == namespaceURI) {
63357                     return n;
63358                   }
63359                 }
63360               }
63361
63362               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
63363             }
63364
63365             return null;
63366           },
63367           // Introduced in DOM Level 3:
63368           lookupNamespaceURI: function lookupNamespaceURI(prefix) {
63369             var el = this;
63370
63371             while (el) {
63372               var map = el._nsMap; //console.dir(map)
63373
63374               if (map) {
63375                 if (prefix in map) {
63376                   return map[prefix];
63377                 }
63378               }
63379
63380               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
63381             }
63382
63383             return null;
63384           },
63385           // Introduced in DOM Level 3:
63386           isDefaultNamespace: function isDefaultNamespace(namespaceURI) {
63387             var prefix = this.lookupPrefix(namespaceURI);
63388             return prefix == null;
63389           }
63390         };
63391
63392         function _xmlEncoder(c) {
63393           return c == '<' && '&lt;' || c == '>' && '&gt;' || c == '&' && '&amp;' || c == '"' && '&quot;' || '&#' + c.charCodeAt() + ';';
63394         }
63395
63396         copy(NodeType, Node);
63397         copy(NodeType, Node.prototype);
63398         /**
63399          * @param callback return true for continue,false for break
63400          * @return boolean true: break visit;
63401          */
63402
63403         function _visitNode(node, callback) {
63404           if (callback(node)) {
63405             return true;
63406           }
63407
63408           if (node = node.firstChild) {
63409             do {
63410               if (_visitNode(node, callback)) {
63411                 return true;
63412               }
63413             } while (node = node.nextSibling);
63414           }
63415         }
63416
63417         function Document() {}
63418
63419         function _onAddAttribute(doc, el, newAttr) {
63420           doc && doc._inc++;
63421           var ns = newAttr.namespaceURI;
63422
63423           if (ns == 'http://www.w3.org/2000/xmlns/') {
63424             //update namespace
63425             el._nsMap[newAttr.prefix ? newAttr.localName : ''] = newAttr.value;
63426           }
63427         }
63428
63429         function _onRemoveAttribute(doc, el, newAttr, remove) {
63430           doc && doc._inc++;
63431           var ns = newAttr.namespaceURI;
63432
63433           if (ns == 'http://www.w3.org/2000/xmlns/') {
63434             //update namespace
63435             delete el._nsMap[newAttr.prefix ? newAttr.localName : ''];
63436           }
63437         }
63438
63439         function _onUpdateChild(doc, el, newChild) {
63440           if (doc && doc._inc) {
63441             doc._inc++; //update childNodes
63442
63443             var cs = el.childNodes;
63444
63445             if (newChild) {
63446               cs[cs.length++] = newChild;
63447             } else {
63448               //console.log(1)
63449               var child = el.firstChild;
63450               var i = 0;
63451
63452               while (child) {
63453                 cs[i++] = child;
63454                 child = child.nextSibling;
63455               }
63456
63457               cs.length = i;
63458             }
63459           }
63460         }
63461         /**
63462          * attributes;
63463          * children;
63464          * 
63465          * writeable properties:
63466          * nodeValue,Attr:value,CharacterData:data
63467          * prefix
63468          */
63469
63470
63471         function _removeChild(parentNode, child) {
63472           var previous = child.previousSibling;
63473           var next = child.nextSibling;
63474
63475           if (previous) {
63476             previous.nextSibling = next;
63477           } else {
63478             parentNode.firstChild = next;
63479           }
63480
63481           if (next) {
63482             next.previousSibling = previous;
63483           } else {
63484             parentNode.lastChild = previous;
63485           }
63486
63487           _onUpdateChild(parentNode.ownerDocument, parentNode);
63488
63489           return child;
63490         }
63491         /**
63492          * preformance key(refChild == null)
63493          */
63494
63495
63496         function _insertBefore(parentNode, newChild, nextChild) {
63497           var cp = newChild.parentNode;
63498
63499           if (cp) {
63500             cp.removeChild(newChild); //remove and update
63501           }
63502
63503           if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
63504             var newFirst = newChild.firstChild;
63505
63506             if (newFirst == null) {
63507               return newChild;
63508             }
63509
63510             var newLast = newChild.lastChild;
63511           } else {
63512             newFirst = newLast = newChild;
63513           }
63514
63515           var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
63516           newFirst.previousSibling = pre;
63517           newLast.nextSibling = nextChild;
63518
63519           if (pre) {
63520             pre.nextSibling = newFirst;
63521           } else {
63522             parentNode.firstChild = newFirst;
63523           }
63524
63525           if (nextChild == null) {
63526             parentNode.lastChild = newLast;
63527           } else {
63528             nextChild.previousSibling = newLast;
63529           }
63530
63531           do {
63532             newFirst.parentNode = parentNode;
63533           } while (newFirst !== newLast && (newFirst = newFirst.nextSibling));
63534
63535           _onUpdateChild(parentNode.ownerDocument || parentNode, parentNode); //console.log(parentNode.lastChild.nextSibling == null)
63536
63537
63538           if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
63539             newChild.firstChild = newChild.lastChild = null;
63540           }
63541
63542           return newChild;
63543         }
63544
63545         function _appendSingleChild(parentNode, newChild) {
63546           var cp = newChild.parentNode;
63547
63548           if (cp) {
63549             var pre = parentNode.lastChild;
63550             cp.removeChild(newChild); //remove and update
63551
63552             var pre = parentNode.lastChild;
63553           }
63554
63555           var pre = parentNode.lastChild;
63556           newChild.parentNode = parentNode;
63557           newChild.previousSibling = pre;
63558           newChild.nextSibling = null;
63559
63560           if (pre) {
63561             pre.nextSibling = newChild;
63562           } else {
63563             parentNode.firstChild = newChild;
63564           }
63565
63566           parentNode.lastChild = newChild;
63567
63568           _onUpdateChild(parentNode.ownerDocument, parentNode, newChild);
63569
63570           return newChild; //console.log("__aa",parentNode.lastChild.nextSibling == null)
63571         }
63572
63573         Document.prototype = {
63574           //implementation : null,
63575           nodeName: '#document',
63576           nodeType: DOCUMENT_NODE,
63577           doctype: null,
63578           documentElement: null,
63579           _inc: 1,
63580           insertBefore: function insertBefore(newChild, refChild) {
63581             //raises 
63582             if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
63583               var child = newChild.firstChild;
63584
63585               while (child) {
63586                 var next = child.nextSibling;
63587                 this.insertBefore(child, refChild);
63588                 child = next;
63589               }
63590
63591               return newChild;
63592             }
63593
63594             if (this.documentElement == null && newChild.nodeType == ELEMENT_NODE) {
63595               this.documentElement = newChild;
63596             }
63597
63598             return _insertBefore(this, newChild, refChild), newChild.ownerDocument = this, newChild;
63599           },
63600           removeChild: function removeChild(oldChild) {
63601             if (this.documentElement == oldChild) {
63602               this.documentElement = null;
63603             }
63604
63605             return _removeChild(this, oldChild);
63606           },
63607           // Introduced in DOM Level 2:
63608           importNode: function importNode(importedNode, deep) {
63609             return _importNode(this, importedNode, deep);
63610           },
63611           // Introduced in DOM Level 2:
63612           getElementById: function getElementById(id) {
63613             var rtv = null;
63614
63615             _visitNode(this.documentElement, function (node) {
63616               if (node.nodeType == ELEMENT_NODE) {
63617                 if (node.getAttribute('id') == id) {
63618                   rtv = node;
63619                   return true;
63620                 }
63621               }
63622             });
63623
63624             return rtv;
63625           },
63626           //document factory method:
63627           createElement: function createElement(tagName) {
63628             var node = new Element();
63629             node.ownerDocument = this;
63630             node.nodeName = tagName;
63631             node.tagName = tagName;
63632             node.childNodes = new NodeList();
63633             var attrs = node.attributes = new NamedNodeMap();
63634             attrs._ownerElement = node;
63635             return node;
63636           },
63637           createDocumentFragment: function createDocumentFragment() {
63638             var node = new DocumentFragment();
63639             node.ownerDocument = this;
63640             node.childNodes = new NodeList();
63641             return node;
63642           },
63643           createTextNode: function createTextNode(data) {
63644             var node = new Text();
63645             node.ownerDocument = this;
63646             node.appendData(data);
63647             return node;
63648           },
63649           createComment: function createComment(data) {
63650             var node = new Comment();
63651             node.ownerDocument = this;
63652             node.appendData(data);
63653             return node;
63654           },
63655           createCDATASection: function createCDATASection(data) {
63656             var node = new CDATASection();
63657             node.ownerDocument = this;
63658             node.appendData(data);
63659             return node;
63660           },
63661           createProcessingInstruction: function createProcessingInstruction(target, data) {
63662             var node = new ProcessingInstruction();
63663             node.ownerDocument = this;
63664             node.tagName = node.target = target;
63665             node.nodeValue = node.data = data;
63666             return node;
63667           },
63668           createAttribute: function createAttribute(name) {
63669             var node = new Attr();
63670             node.ownerDocument = this;
63671             node.name = name;
63672             node.nodeName = name;
63673             node.localName = name;
63674             node.specified = true;
63675             return node;
63676           },
63677           createEntityReference: function createEntityReference(name) {
63678             var node = new EntityReference();
63679             node.ownerDocument = this;
63680             node.nodeName = name;
63681             return node;
63682           },
63683           // Introduced in DOM Level 2:
63684           createElementNS: function createElementNS(namespaceURI, qualifiedName) {
63685             var node = new Element();
63686             var pl = qualifiedName.split(':');
63687             var attrs = node.attributes = new NamedNodeMap();
63688             node.childNodes = new NodeList();
63689             node.ownerDocument = this;
63690             node.nodeName = qualifiedName;
63691             node.tagName = qualifiedName;
63692             node.namespaceURI = namespaceURI;
63693
63694             if (pl.length == 2) {
63695               node.prefix = pl[0];
63696               node.localName = pl[1];
63697             } else {
63698               //el.prefix = null;
63699               node.localName = qualifiedName;
63700             }
63701
63702             attrs._ownerElement = node;
63703             return node;
63704           },
63705           // Introduced in DOM Level 2:
63706           createAttributeNS: function createAttributeNS(namespaceURI, qualifiedName) {
63707             var node = new Attr();
63708             var pl = qualifiedName.split(':');
63709             node.ownerDocument = this;
63710             node.nodeName = qualifiedName;
63711             node.name = qualifiedName;
63712             node.namespaceURI = namespaceURI;
63713             node.specified = true;
63714
63715             if (pl.length == 2) {
63716               node.prefix = pl[0];
63717               node.localName = pl[1];
63718             } else {
63719               //el.prefix = null;
63720               node.localName = qualifiedName;
63721             }
63722
63723             return node;
63724           }
63725         };
63726
63727         _extends(Document, Node);
63728
63729         function Element() {
63730           this._nsMap = {};
63731         }
63732         Element.prototype = {
63733           nodeType: ELEMENT_NODE,
63734           hasAttribute: function hasAttribute(name) {
63735             return this.getAttributeNode(name) != null;
63736           },
63737           getAttribute: function getAttribute(name) {
63738             var attr = this.getAttributeNode(name);
63739             return attr && attr.value || '';
63740           },
63741           getAttributeNode: function getAttributeNode(name) {
63742             return this.attributes.getNamedItem(name);
63743           },
63744           setAttribute: function setAttribute(name, value) {
63745             var attr = this.ownerDocument.createAttribute(name);
63746             attr.value = attr.nodeValue = "" + value;
63747             this.setAttributeNode(attr);
63748           },
63749           removeAttribute: function removeAttribute(name) {
63750             var attr = this.getAttributeNode(name);
63751             attr && this.removeAttributeNode(attr);
63752           },
63753           //four real opeartion method
63754           appendChild: function appendChild(newChild) {
63755             if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
63756               return this.insertBefore(newChild, null);
63757             } else {
63758               return _appendSingleChild(this, newChild);
63759             }
63760           },
63761           setAttributeNode: function setAttributeNode(newAttr) {
63762             return this.attributes.setNamedItem(newAttr);
63763           },
63764           setAttributeNodeNS: function setAttributeNodeNS(newAttr) {
63765             return this.attributes.setNamedItemNS(newAttr);
63766           },
63767           removeAttributeNode: function removeAttributeNode(oldAttr) {
63768             //console.log(this == oldAttr.ownerElement)
63769             return this.attributes.removeNamedItem(oldAttr.nodeName);
63770           },
63771           //get real attribute name,and remove it by removeAttributeNode
63772           removeAttributeNS: function removeAttributeNS(namespaceURI, localName) {
63773             var old = this.getAttributeNodeNS(namespaceURI, localName);
63774             old && this.removeAttributeNode(old);
63775           },
63776           hasAttributeNS: function hasAttributeNS(namespaceURI, localName) {
63777             return this.getAttributeNodeNS(namespaceURI, localName) != null;
63778           },
63779           getAttributeNS: function getAttributeNS(namespaceURI, localName) {
63780             var attr = this.getAttributeNodeNS(namespaceURI, localName);
63781             return attr && attr.value || '';
63782           },
63783           setAttributeNS: function setAttributeNS(namespaceURI, qualifiedName, value) {
63784             var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
63785             attr.value = attr.nodeValue = "" + value;
63786             this.setAttributeNode(attr);
63787           },
63788           getAttributeNodeNS: function getAttributeNodeNS(namespaceURI, localName) {
63789             return this.attributes.getNamedItemNS(namespaceURI, localName);
63790           },
63791           getElementsByTagName: function getElementsByTagName(tagName) {
63792             return new LiveNodeList(this, function (base) {
63793               var ls = [];
63794
63795               _visitNode(base, function (node) {
63796                 if (node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)) {
63797                   ls.push(node);
63798                 }
63799               });
63800
63801               return ls;
63802             });
63803           },
63804           getElementsByTagNameNS: function getElementsByTagNameNS(namespaceURI, localName) {
63805             return new LiveNodeList(this, function (base) {
63806               var ls = [];
63807
63808               _visitNode(base, function (node) {
63809                 if (node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)) {
63810                   ls.push(node);
63811                 }
63812               });
63813
63814               return ls;
63815             });
63816           }
63817         };
63818         Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
63819         Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
63820
63821         _extends(Element, Node);
63822
63823         function Attr() {}
63824         Attr.prototype.nodeType = ATTRIBUTE_NODE;
63825
63826         _extends(Attr, Node);
63827
63828         function CharacterData() {}
63829         CharacterData.prototype = {
63830           data: '',
63831           substringData: function substringData(offset, count) {
63832             return this.data.substring(offset, offset + count);
63833           },
63834           appendData: function appendData(text) {
63835             text = this.data + text;
63836             this.nodeValue = this.data = text;
63837             this.length = text.length;
63838           },
63839           insertData: function insertData(offset, text) {
63840             this.replaceData(offset, 0, text);
63841           },
63842           appendChild: function appendChild(newChild) {
63843             throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR]);
63844           },
63845           deleteData: function deleteData(offset, count) {
63846             this.replaceData(offset, count, "");
63847           },
63848           replaceData: function replaceData(offset, count, text) {
63849             var start = this.data.substring(0, offset);
63850             var end = this.data.substring(offset + count);
63851             text = start + text + end;
63852             this.nodeValue = this.data = text;
63853             this.length = text.length;
63854           }
63855         };
63856
63857         _extends(CharacterData, Node);
63858
63859         function Text() {}
63860         Text.prototype = {
63861           nodeName: "#text",
63862           nodeType: TEXT_NODE,
63863           splitText: function splitText(offset) {
63864             var text = this.data;
63865             var newText = text.substring(offset);
63866             text = text.substring(0, offset);
63867             this.data = this.nodeValue = text;
63868             this.length = text.length;
63869             var newNode = this.ownerDocument.createTextNode(newText);
63870
63871             if (this.parentNode) {
63872               this.parentNode.insertBefore(newNode, this.nextSibling);
63873             }
63874
63875             return newNode;
63876           }
63877         };
63878
63879         _extends(Text, CharacterData);
63880
63881         function Comment() {}
63882         Comment.prototype = {
63883           nodeName: "#comment",
63884           nodeType: COMMENT_NODE
63885         };
63886
63887         _extends(Comment, CharacterData);
63888
63889         function CDATASection() {}
63890         CDATASection.prototype = {
63891           nodeName: "#cdata-section",
63892           nodeType: CDATA_SECTION_NODE
63893         };
63894
63895         _extends(CDATASection, CharacterData);
63896
63897         function DocumentType() {}
63898         DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
63899
63900         _extends(DocumentType, Node);
63901
63902         function Notation() {}
63903         Notation.prototype.nodeType = NOTATION_NODE;
63904
63905         _extends(Notation, Node);
63906
63907         function Entity() {}
63908         Entity.prototype.nodeType = ENTITY_NODE;
63909
63910         _extends(Entity, Node);
63911
63912         function EntityReference() {}
63913         EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
63914
63915         _extends(EntityReference, Node);
63916
63917         function DocumentFragment() {}
63918         DocumentFragment.prototype.nodeName = "#document-fragment";
63919         DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE;
63920
63921         _extends(DocumentFragment, Node);
63922
63923         function ProcessingInstruction() {}
63924
63925         ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
63926
63927         _extends(ProcessingInstruction, Node);
63928
63929         function XMLSerializer$1() {}
63930
63931         XMLSerializer$1.prototype.serializeToString = function (node, isHtml, nodeFilter) {
63932           return nodeSerializeToString.call(node, isHtml, nodeFilter);
63933         };
63934
63935         Node.prototype.toString = nodeSerializeToString;
63936
63937         function nodeSerializeToString(isHtml, nodeFilter) {
63938           var buf = [];
63939           var refNode = this.nodeType == 9 ? this.documentElement : this;
63940           var prefix = refNode.prefix;
63941           var uri = refNode.namespaceURI;
63942
63943           if (uri && prefix == null) {
63944             //console.log(prefix)
63945             var prefix = refNode.lookupPrefix(uri);
63946
63947             if (prefix == null) {
63948               //isHTML = true;
63949               var visibleNamespaces = [{
63950                 namespace: uri,
63951                 prefix: null
63952               } //{namespace:uri,prefix:''}
63953               ];
63954             }
63955           }
63956
63957           serializeToString(this, buf, isHtml, nodeFilter, visibleNamespaces); //console.log('###',this.nodeType,uri,prefix,buf.join(''))
63958
63959           return buf.join('');
63960         }
63961
63962         function needNamespaceDefine(node, isHTML, visibleNamespaces) {
63963           var prefix = node.prefix || '';
63964           var uri = node.namespaceURI;
63965
63966           if (!prefix && !uri) {
63967             return false;
63968           }
63969
63970           if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" || uri == 'http://www.w3.org/2000/xmlns/') {
63971             return false;
63972           }
63973
63974           var i = visibleNamespaces.length; //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces)
63975
63976           while (i--) {
63977             var ns = visibleNamespaces[i]; // get namespace prefix
63978             //console.log(node.nodeType,node.tagName,ns.prefix,prefix)
63979
63980             if (ns.prefix == prefix) {
63981               return ns.namespace != uri;
63982             }
63983           } //console.log(isHTML,uri,prefix=='')
63984           //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){
63985           //    return false;
63986           //}
63987           //node.flag = '11111'
63988           //console.error(3,true,node.flag,node.prefix,node.namespaceURI)
63989
63990
63991           return true;
63992         }
63993
63994         function serializeToString(node, buf, isHTML, nodeFilter, visibleNamespaces) {
63995           if (nodeFilter) {
63996             node = nodeFilter(node);
63997
63998             if (node) {
63999               if (typeof node == 'string') {
64000                 buf.push(node);
64001                 return;
64002               }
64003             } else {
64004               return;
64005             } //buf.sort.apply(attrs, attributeSorter);
64006
64007           }
64008
64009           switch (node.nodeType) {
64010             case ELEMENT_NODE:
64011               if (!visibleNamespaces) visibleNamespaces = [];
64012               visibleNamespaces.length;
64013               var attrs = node.attributes;
64014               var len = attrs.length;
64015               var child = node.firstChild;
64016               var nodeName = node.tagName;
64017               isHTML = htmlns === node.namespaceURI || isHTML;
64018               buf.push('<', nodeName);
64019
64020               for (var i = 0; i < len; i++) {
64021                 // add namespaces for attributes
64022                 var attr = attrs.item(i);
64023
64024                 if (attr.prefix == 'xmlns') {
64025                   visibleNamespaces.push({
64026                     prefix: attr.localName,
64027                     namespace: attr.value
64028                   });
64029                 } else if (attr.nodeName == 'xmlns') {
64030                   visibleNamespaces.push({
64031                     prefix: '',
64032                     namespace: attr.value
64033                   });
64034                 }
64035               }
64036
64037               for (var i = 0; i < len; i++) {
64038                 var attr = attrs.item(i);
64039
64040                 if (needNamespaceDefine(attr, isHTML, visibleNamespaces)) {
64041                   var prefix = attr.prefix || '';
64042                   var uri = attr.namespaceURI;
64043                   var ns = prefix ? ' xmlns:' + prefix : " xmlns";
64044                   buf.push(ns, '="', uri, '"');
64045                   visibleNamespaces.push({
64046                     prefix: prefix,
64047                     namespace: uri
64048                   });
64049                 }
64050
64051                 serializeToString(attr, buf, isHTML, nodeFilter, visibleNamespaces);
64052               } // add namespace for current node               
64053
64054
64055               if (needNamespaceDefine(node, isHTML, visibleNamespaces)) {
64056                 var prefix = node.prefix || '';
64057                 var uri = node.namespaceURI;
64058                 var ns = prefix ? ' xmlns:' + prefix : " xmlns";
64059                 buf.push(ns, '="', uri, '"');
64060                 visibleNamespaces.push({
64061                   prefix: prefix,
64062                   namespace: uri
64063                 });
64064               }
64065
64066               if (child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)) {
64067                 buf.push('>'); //if is cdata child node
64068
64069                 if (isHTML && /^script$/i.test(nodeName)) {
64070                   while (child) {
64071                     if (child.data) {
64072                       buf.push(child.data);
64073                     } else {
64074                       serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
64075                     }
64076
64077                     child = child.nextSibling;
64078                   }
64079                 } else {
64080                   while (child) {
64081                     serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
64082                     child = child.nextSibling;
64083                   }
64084                 }
64085
64086                 buf.push('</', nodeName, '>');
64087               } else {
64088                 buf.push('/>');
64089               } // remove added visible namespaces
64090               //visibleNamespaces.length = startVisibleNamespaces;
64091
64092
64093               return;
64094
64095             case DOCUMENT_NODE:
64096             case DOCUMENT_FRAGMENT_NODE:
64097               var child = node.firstChild;
64098
64099               while (child) {
64100                 serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
64101                 child = child.nextSibling;
64102               }
64103
64104               return;
64105
64106             case ATTRIBUTE_NODE:
64107               return buf.push(' ', node.name, '="', node.value.replace(/[<&"]/g, _xmlEncoder), '"');
64108
64109             case TEXT_NODE:
64110               return buf.push(node.data.replace(/[<&]/g, _xmlEncoder));
64111
64112             case CDATA_SECTION_NODE:
64113               return buf.push('<![CDATA[', node.data, ']]>');
64114
64115             case COMMENT_NODE:
64116               return buf.push("<!--", node.data, "-->");
64117
64118             case DOCUMENT_TYPE_NODE:
64119               var pubid = node.publicId;
64120               var sysid = node.systemId;
64121               buf.push('<!DOCTYPE ', node.name);
64122
64123               if (pubid) {
64124                 buf.push(' PUBLIC "', pubid);
64125
64126                 if (sysid && sysid != '.') {
64127                   buf.push('" "', sysid);
64128                 }
64129
64130                 buf.push('">');
64131               } else if (sysid && sysid != '.') {
64132                 buf.push(' SYSTEM "', sysid, '">');
64133               } else {
64134                 var sub = node.internalSubset;
64135
64136                 if (sub) {
64137                   buf.push(" [", sub, "]");
64138                 }
64139
64140                 buf.push(">");
64141               }
64142
64143               return;
64144
64145             case PROCESSING_INSTRUCTION_NODE:
64146               return buf.push("<?", node.target, " ", node.data, "?>");
64147
64148             case ENTITY_REFERENCE_NODE:
64149               return buf.push('&', node.nodeName, ';');
64150             //case ENTITY_NODE:
64151             //case NOTATION_NODE:
64152
64153             default:
64154               buf.push('??', node.nodeName);
64155           }
64156         }
64157
64158         function _importNode(doc, node, deep) {
64159           var node2;
64160
64161           switch (node.nodeType) {
64162             case ELEMENT_NODE:
64163               node2 = node.cloneNode(false);
64164               node2.ownerDocument = doc;
64165             //var attrs = node2.attributes;
64166             //var len = attrs.length;
64167             //for(var i=0;i<len;i++){
64168             //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
64169             //}
64170
64171             case DOCUMENT_FRAGMENT_NODE:
64172               break;
64173
64174             case ATTRIBUTE_NODE:
64175               deep = true;
64176               break;
64177             //case ENTITY_REFERENCE_NODE:
64178             //case PROCESSING_INSTRUCTION_NODE:
64179             ////case TEXT_NODE:
64180             //case CDATA_SECTION_NODE:
64181             //case COMMENT_NODE:
64182             //  deep = false;
64183             //  break;
64184             //case DOCUMENT_NODE:
64185             //case DOCUMENT_TYPE_NODE:
64186             //cannot be imported.
64187             //case ENTITY_NODE:
64188             //case NOTATION_NODE:
64189             //can not hit in level3
64190             //default:throw e;
64191           }
64192
64193           if (!node2) {
64194             node2 = node.cloneNode(false); //false
64195           }
64196
64197           node2.ownerDocument = doc;
64198           node2.parentNode = null;
64199
64200           if (deep) {
64201             var child = node.firstChild;
64202
64203             while (child) {
64204               node2.appendChild(_importNode(doc, child, deep));
64205               child = child.nextSibling;
64206             }
64207           }
64208
64209           return node2;
64210         } //
64211         //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
64212         //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
64213
64214
64215         function _cloneNode(doc, node, deep) {
64216           var node2 = new node.constructor();
64217
64218           for (var n in node) {
64219             var v = node[n];
64220
64221             if (_typeof(v) != 'object') {
64222               if (v != node2[n]) {
64223                 node2[n] = v;
64224               }
64225             }
64226           }
64227
64228           if (node.childNodes) {
64229             node2.childNodes = new NodeList();
64230           }
64231
64232           node2.ownerDocument = doc;
64233
64234           switch (node2.nodeType) {
64235             case ELEMENT_NODE:
64236               var attrs = node.attributes;
64237               var attrs2 = node2.attributes = new NamedNodeMap();
64238               var len = attrs.length;
64239               attrs2._ownerElement = node2;
64240
64241               for (var i = 0; i < len; i++) {
64242                 node2.setAttributeNode(_cloneNode(doc, attrs.item(i), true));
64243               }
64244
64245               break;
64246
64247             case ATTRIBUTE_NODE:
64248               deep = true;
64249           }
64250
64251           if (deep) {
64252             var child = node.firstChild;
64253
64254             while (child) {
64255               node2.appendChild(_cloneNode(doc, child, deep));
64256               child = child.nextSibling;
64257             }
64258           }
64259
64260           return node2;
64261         }
64262
64263         function __set__(object, key, value) {
64264           object[key] = value;
64265         } //do dynamic
64266
64267
64268         try {
64269           if (Object.defineProperty) {
64270             var getTextContent = function getTextContent(node) {
64271               switch (node.nodeType) {
64272                 case ELEMENT_NODE:
64273                 case DOCUMENT_FRAGMENT_NODE:
64274                   var buf = [];
64275                   node = node.firstChild;
64276
64277                   while (node) {
64278                     if (node.nodeType !== 7 && node.nodeType !== 8) {
64279                       buf.push(getTextContent(node));
64280                     }
64281
64282                     node = node.nextSibling;
64283                   }
64284
64285                   return buf.join('');
64286
64287                 default:
64288                   return node.nodeValue;
64289               }
64290             };
64291
64292             Object.defineProperty(LiveNodeList.prototype, 'length', {
64293               get: function get() {
64294                 _updateLiveList(this);
64295
64296                 return this.$$length;
64297               }
64298             });
64299             Object.defineProperty(Node.prototype, 'textContent', {
64300               get: function get() {
64301                 return getTextContent(this);
64302               },
64303               set: function set(data) {
64304                 switch (this.nodeType) {
64305                   case ELEMENT_NODE:
64306                   case DOCUMENT_FRAGMENT_NODE:
64307                     while (this.firstChild) {
64308                       this.removeChild(this.firstChild);
64309                     }
64310
64311                     if (data || String(data)) {
64312                       this.appendChild(this.ownerDocument.createTextNode(data));
64313                     }
64314
64315                     break;
64316
64317                   default:
64318                     //TODO:
64319                     this.data = data;
64320                     this.value = data;
64321                     this.nodeValue = data;
64322                 }
64323               }
64324             });
64325
64326             __set__ = function __set__(object, key, value) {
64327               //console.log(value)
64328               object['$$' + key] = value;
64329             };
64330           }
64331         } catch (e) {//ie8
64332         } //if(typeof require == 'function'){
64333
64334
64335         var DOMImplementation_1 = DOMImplementation;
64336         var XMLSerializer_1 = XMLSerializer$1; //}
64337
64338         var dom = {
64339           DOMImplementation: DOMImplementation_1,
64340           XMLSerializer: XMLSerializer_1
64341         };
64342
64343         var domParser = createCommonjsModule(function (module, exports) {
64344           function DOMParser(options) {
64345             this.options = options || {
64346               locator: {}
64347             };
64348           }
64349
64350           DOMParser.prototype.parseFromString = function (source, mimeType) {
64351             var options = this.options;
64352             var sax = new XMLReader();
64353             var domBuilder = options.domBuilder || new DOMHandler(); //contentHandler and LexicalHandler
64354
64355             var errorHandler = options.errorHandler;
64356             var locator = options.locator;
64357             var defaultNSMap = options.xmlns || {};
64358             var entityMap = {
64359               'lt': '<',
64360               'gt': '>',
64361               'amp': '&',
64362               'quot': '"',
64363               'apos': "'"
64364             };
64365
64366             if (locator) {
64367               domBuilder.setDocumentLocator(locator);
64368             }
64369
64370             sax.errorHandler = buildErrorHandler(errorHandler, domBuilder, locator);
64371             sax.domBuilder = options.domBuilder || domBuilder;
64372
64373             if (/\/x?html?$/.test(mimeType)) {
64374               entityMap.nbsp = '\xa0';
64375               entityMap.copy = '\xa9';
64376               defaultNSMap[''] = 'http://www.w3.org/1999/xhtml';
64377             }
64378
64379             defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
64380
64381             if (source) {
64382               sax.parse(source, defaultNSMap, entityMap);
64383             } else {
64384               sax.errorHandler.error("invalid doc source");
64385             }
64386
64387             return domBuilder.doc;
64388           };
64389
64390           function buildErrorHandler(errorImpl, domBuilder, locator) {
64391             if (!errorImpl) {
64392               if (domBuilder instanceof DOMHandler) {
64393                 return domBuilder;
64394               }
64395
64396               errorImpl = domBuilder;
64397             }
64398
64399             var errorHandler = {};
64400             var isCallback = errorImpl instanceof Function;
64401             locator = locator || {};
64402
64403             function build(key) {
64404               var fn = errorImpl[key];
64405
64406               if (!fn && isCallback) {
64407                 fn = errorImpl.length == 2 ? function (msg) {
64408                   errorImpl(key, msg);
64409                 } : errorImpl;
64410               }
64411
64412               errorHandler[key] = fn && function (msg) {
64413                 fn('[xmldom ' + key + ']\t' + msg + _locator(locator));
64414               } || function () {};
64415             }
64416
64417             build('warning');
64418             build('error');
64419             build('fatalError');
64420             return errorHandler;
64421           } //console.log('#\n\n\n\n\n\n\n####')
64422
64423           /**
64424            * +ContentHandler+ErrorHandler
64425            * +LexicalHandler+EntityResolver2
64426            * -DeclHandler-DTDHandler 
64427            * 
64428            * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
64429            * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
64430            * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
64431            */
64432
64433
64434           function DOMHandler() {
64435             this.cdata = false;
64436           }
64437
64438           function position(locator, node) {
64439             node.lineNumber = locator.lineNumber;
64440             node.columnNumber = locator.columnNumber;
64441           }
64442           /**
64443            * @see org.xml.sax.ContentHandler#startDocument
64444            * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
64445            */
64446
64447
64448           DOMHandler.prototype = {
64449             startDocument: function startDocument() {
64450               this.doc = new DOMImplementation().createDocument(null, null, null);
64451
64452               if (this.locator) {
64453                 this.doc.documentURI = this.locator.systemId;
64454               }
64455             },
64456             startElement: function startElement(namespaceURI, localName, qName, attrs) {
64457               var doc = this.doc;
64458               var el = doc.createElementNS(namespaceURI, qName || localName);
64459               var len = attrs.length;
64460               appendElement(this, el);
64461               this.currentElement = el;
64462               this.locator && position(this.locator, el);
64463
64464               for (var i = 0; i < len; i++) {
64465                 var namespaceURI = attrs.getURI(i);
64466                 var value = attrs.getValue(i);
64467                 var qName = attrs.getQName(i);
64468                 var attr = doc.createAttributeNS(namespaceURI, qName);
64469                 this.locator && position(attrs.getLocator(i), attr);
64470                 attr.value = attr.nodeValue = value;
64471                 el.setAttributeNode(attr);
64472               }
64473             },
64474             endElement: function endElement(namespaceURI, localName, qName) {
64475               var current = this.currentElement;
64476               current.tagName;
64477               this.currentElement = current.parentNode;
64478             },
64479             startPrefixMapping: function startPrefixMapping(prefix, uri) {},
64480             endPrefixMapping: function endPrefixMapping(prefix) {},
64481             processingInstruction: function processingInstruction(target, data) {
64482               var ins = this.doc.createProcessingInstruction(target, data);
64483               this.locator && position(this.locator, ins);
64484               appendElement(this, ins);
64485             },
64486             ignorableWhitespace: function ignorableWhitespace(ch, start, length) {},
64487             characters: function characters(chars, start, length) {
64488               chars = _toString.apply(this, arguments); //console.log(chars)
64489
64490               if (chars) {
64491                 if (this.cdata) {
64492                   var charNode = this.doc.createCDATASection(chars);
64493                 } else {
64494                   var charNode = this.doc.createTextNode(chars);
64495                 }
64496
64497                 if (this.currentElement) {
64498                   this.currentElement.appendChild(charNode);
64499                 } else if (/^\s*$/.test(chars)) {
64500                   this.doc.appendChild(charNode); //process xml
64501                 }
64502
64503                 this.locator && position(this.locator, charNode);
64504               }
64505             },
64506             skippedEntity: function skippedEntity(name) {},
64507             endDocument: function endDocument() {
64508               this.doc.normalize();
64509             },
64510             setDocumentLocator: function setDocumentLocator(locator) {
64511               if (this.locator = locator) {
64512                 // && !('lineNumber' in locator)){
64513                 locator.lineNumber = 0;
64514               }
64515             },
64516             //LexicalHandler
64517             comment: function comment(chars, start, length) {
64518               chars = _toString.apply(this, arguments);
64519               var comm = this.doc.createComment(chars);
64520               this.locator && position(this.locator, comm);
64521               appendElement(this, comm);
64522             },
64523             startCDATA: function startCDATA() {
64524               //used in characters() methods
64525               this.cdata = true;
64526             },
64527             endCDATA: function endCDATA() {
64528               this.cdata = false;
64529             },
64530             startDTD: function startDTD(name, publicId, systemId) {
64531               var impl = this.doc.implementation;
64532
64533               if (impl && impl.createDocumentType) {
64534                 var dt = impl.createDocumentType(name, publicId, systemId);
64535                 this.locator && position(this.locator, dt);
64536                 appendElement(this, dt);
64537               }
64538             },
64539
64540             /**
64541              * @see org.xml.sax.ErrorHandler
64542              * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
64543              */
64544             warning: function warning(error) {
64545               console.warn('[xmldom warning]\t' + error, _locator(this.locator));
64546             },
64547             error: function error(_error) {
64548               console.error('[xmldom error]\t' + _error, _locator(this.locator));
64549             },
64550             fatalError: function fatalError(error) {
64551               console.error('[xmldom fatalError]\t' + error, _locator(this.locator));
64552               throw error;
64553             }
64554           };
64555
64556           function _locator(l) {
64557             if (l) {
64558               return '\n@' + (l.systemId || '') + '#[line:' + l.lineNumber + ',col:' + l.columnNumber + ']';
64559             }
64560           }
64561
64562           function _toString(chars, start, length) {
64563             if (typeof chars == 'string') {
64564               return chars.substr(start, length);
64565             } else {
64566               //java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
64567               if (chars.length >= start + length || start) {
64568                 return new java.lang.String(chars, start, length) + '';
64569               }
64570
64571               return chars;
64572             }
64573           }
64574           /*
64575            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
64576            * used method of org.xml.sax.ext.LexicalHandler:
64577            *  #comment(chars, start, length)
64578            *  #startCDATA()
64579            *  #endCDATA()
64580            *  #startDTD(name, publicId, systemId)
64581            *
64582            *
64583            * IGNORED method of org.xml.sax.ext.LexicalHandler:
64584            *  #endDTD()
64585            *  #startEntity(name)
64586            *  #endEntity(name)
64587            *
64588            *
64589            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
64590            * IGNORED method of org.xml.sax.ext.DeclHandler
64591            *    #attributeDecl(eName, aName, type, mode, value)
64592            *  #elementDecl(name, model)
64593            *  #externalEntityDecl(name, publicId, systemId)
64594            *  #internalEntityDecl(name, value)
64595            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
64596            * IGNORED method of org.xml.sax.EntityResolver2
64597            *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
64598            *  #resolveEntity(publicId, systemId)
64599            *  #getExternalSubset(name, baseURI)
64600            * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
64601            * IGNORED method of org.xml.sax.DTDHandler
64602            *  #notationDecl(name, publicId, systemId) {};
64603            *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
64604            */
64605
64606
64607           "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g, function (key) {
64608             DOMHandler.prototype[key] = function () {
64609               return null;
64610             };
64611           });
64612           /* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
64613
64614           function appendElement(hander, node) {
64615             if (!hander.currentElement) {
64616               hander.doc.appendChild(node);
64617             } else {
64618               hander.currentElement.appendChild(node);
64619             }
64620           } //appendChild and setAttributeNS are preformance key
64621           //if(typeof require == 'function'){
64622
64623
64624           var XMLReader = sax.XMLReader;
64625           var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
64626           exports.XMLSerializer = dom.XMLSerializer;
64627           exports.DOMParser = DOMParser; //}
64628         });
64629
64630         var togeojson = createCommonjsModule(function (module, exports) {
64631           var toGeoJSON = function () {
64632
64633             var removeSpace = /\s*/g,
64634                 trimSpace = /^\s*|\s*$/g,
64635                 splitSpace = /\s+/; // generate a short, numeric hash of a string
64636
64637             function okhash(x) {
64638               if (!x || !x.length) return 0;
64639
64640               for (var i = 0, h = 0; i < x.length; i++) {
64641                 h = (h << 5) - h + x.charCodeAt(i) | 0;
64642               }
64643
64644               return h;
64645             } // all Y children of X
64646
64647
64648             function get(x, y) {
64649               return x.getElementsByTagName(y);
64650             }
64651
64652             function attr(x, y) {
64653               return x.getAttribute(y);
64654             }
64655
64656             function attrf(x, y) {
64657               return parseFloat(attr(x, y));
64658             } // one Y child of X, if any, otherwise null
64659
64660
64661             function get1(x, y) {
64662               var n = get(x, y);
64663               return n.length ? n[0] : null;
64664             } // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
64665
64666
64667             function norm(el) {
64668               if (el.normalize) {
64669                 el.normalize();
64670               }
64671
64672               return el;
64673             } // cast array x into numbers
64674
64675
64676             function numarray(x) {
64677               for (var j = 0, o = []; j < x.length; j++) {
64678                 o[j] = parseFloat(x[j]);
64679               }
64680
64681               return o;
64682             } // get the content of a text node, if any
64683
64684
64685             function nodeVal(x) {
64686               if (x) {
64687                 norm(x);
64688               }
64689
64690               return x && x.textContent || '';
64691             } // get the contents of multiple text nodes, if present
64692
64693
64694             function getMulti(x, ys) {
64695               var o = {},
64696                   n,
64697                   k;
64698
64699               for (k = 0; k < ys.length; k++) {
64700                 n = get1(x, ys[k]);
64701                 if (n) o[ys[k]] = nodeVal(n);
64702               }
64703
64704               return o;
64705             } // add properties of Y to X, overwriting if present in both
64706
64707
64708             function extend(x, y) {
64709               for (var k in y) {
64710                 x[k] = y[k];
64711               }
64712             } // get one coordinate from a coordinate array, if any
64713
64714
64715             function coord1(v) {
64716               return numarray(v.replace(removeSpace, '').split(','));
64717             } // get all coordinates from a coordinate array as [[],[]]
64718
64719
64720             function coord(v) {
64721               var coords = v.replace(trimSpace, '').split(splitSpace),
64722                   o = [];
64723
64724               for (var i = 0; i < coords.length; i++) {
64725                 o.push(coord1(coords[i]));
64726               }
64727
64728               return o;
64729             }
64730
64731             function coordPair(x) {
64732               var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
64733                   ele = get1(x, 'ele'),
64734                   // handle namespaced attribute in browser
64735               heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
64736                   time = get1(x, 'time'),
64737                   e;
64738
64739               if (ele) {
64740                 e = parseFloat(nodeVal(ele));
64741
64742                 if (!isNaN(e)) {
64743                   ll.push(e);
64744                 }
64745               }
64746
64747               return {
64748                 coordinates: ll,
64749                 time: time ? nodeVal(time) : null,
64750                 heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
64751               };
64752             } // create a new feature collection parent object
64753
64754
64755             function fc() {
64756               return {
64757                 type: 'FeatureCollection',
64758                 features: []
64759               };
64760             }
64761
64762             var serializer;
64763
64764             if (typeof XMLSerializer !== 'undefined') {
64765               /* istanbul ignore next */
64766               serializer = new XMLSerializer(); // only require xmldom in a node environment
64767             } else if ((typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && !process.browser) {
64768               serializer = new domParser.XMLSerializer();
64769             }
64770
64771             function xml2str(str) {
64772               // IE9 will create a new XMLSerializer but it'll crash immediately.
64773               // This line is ignored because we don't run coverage tests in IE9
64774
64775               /* istanbul ignore next */
64776               if (str.xml !== undefined) return str.xml;
64777               return serializer.serializeToString(str);
64778             }
64779
64780             var t = {
64781               kml: function kml(doc) {
64782                 var gj = fc(),
64783                     // styleindex keeps track of hashed styles in order to match features
64784                 styleIndex = {},
64785                     styleByHash = {},
64786                     // stylemapindex keeps track of style maps to expose in properties
64787                 styleMapIndex = {},
64788                     // atomic geospatial types supported by KML - MultiGeometry is
64789                 // handled separately
64790                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
64791                     // all root placemarks in the file
64792                 placemarks = get(doc, 'Placemark'),
64793                     styles = get(doc, 'Style'),
64794                     styleMaps = get(doc, 'StyleMap');
64795
64796                 for (var k = 0; k < styles.length; k++) {
64797                   var hash = okhash(xml2str(styles[k])).toString(16);
64798                   styleIndex['#' + attr(styles[k], 'id')] = hash;
64799                   styleByHash[hash] = styles[k];
64800                 }
64801
64802                 for (var l = 0; l < styleMaps.length; l++) {
64803                   styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
64804                   var pairs = get(styleMaps[l], 'Pair');
64805                   var pairsMap = {};
64806
64807                   for (var m = 0; m < pairs.length; m++) {
64808                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
64809                   }
64810
64811                   styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
64812                 }
64813
64814                 for (var j = 0; j < placemarks.length; j++) {
64815                   gj.features = gj.features.concat(getPlacemark(placemarks[j]));
64816                 }
64817
64818                 function kmlColor(v) {
64819                   var color, opacity;
64820                   v = v || '';
64821
64822                   if (v.substr(0, 1) === '#') {
64823                     v = v.substr(1);
64824                   }
64825
64826                   if (v.length === 6 || v.length === 3) {
64827                     color = v;
64828                   }
64829
64830                   if (v.length === 8) {
64831                     opacity = parseInt(v.substr(0, 2), 16) / 255;
64832                     color = '#' + v.substr(6, 2) + v.substr(4, 2) + v.substr(2, 2);
64833                   }
64834
64835                   return [color, isNaN(opacity) ? undefined : opacity];
64836                 }
64837
64838                 function gxCoord(v) {
64839                   return numarray(v.split(' '));
64840                 }
64841
64842                 function gxCoords(root) {
64843                   var elems = get(root, 'coord'),
64844                       coords = [],
64845                       times = [];
64846                   if (elems.length === 0) elems = get(root, 'gx:coord');
64847
64848                   for (var i = 0; i < elems.length; i++) {
64849                     coords.push(gxCoord(nodeVal(elems[i])));
64850                   }
64851
64852                   var timeElems = get(root, 'when');
64853
64854                   for (var j = 0; j < timeElems.length; j++) {
64855                     times.push(nodeVal(timeElems[j]));
64856                   }
64857
64858                   return {
64859                     coords: coords,
64860                     times: times
64861                   };
64862                 }
64863
64864                 function getGeometry(root) {
64865                   var geomNode,
64866                       geomNodes,
64867                       i,
64868                       j,
64869                       k,
64870                       geoms = [],
64871                       coordTimes = [];
64872
64873                   if (get1(root, 'MultiGeometry')) {
64874                     return getGeometry(get1(root, 'MultiGeometry'));
64875                   }
64876
64877                   if (get1(root, 'MultiTrack')) {
64878                     return getGeometry(get1(root, 'MultiTrack'));
64879                   }
64880
64881                   if (get1(root, 'gx:MultiTrack')) {
64882                     return getGeometry(get1(root, 'gx:MultiTrack'));
64883                   }
64884
64885                   for (i = 0; i < geotypes.length; i++) {
64886                     geomNodes = get(root, geotypes[i]);
64887
64888                     if (geomNodes) {
64889                       for (j = 0; j < geomNodes.length; j++) {
64890                         geomNode = geomNodes[j];
64891
64892                         if (geotypes[i] === 'Point') {
64893                           geoms.push({
64894                             type: 'Point',
64895                             coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
64896                           });
64897                         } else if (geotypes[i] === 'LineString') {
64898                           geoms.push({
64899                             type: 'LineString',
64900                             coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
64901                           });
64902                         } else if (geotypes[i] === 'Polygon') {
64903                           var rings = get(geomNode, 'LinearRing'),
64904                               coords = [];
64905
64906                           for (k = 0; k < rings.length; k++) {
64907                             coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
64908                           }
64909
64910                           geoms.push({
64911                             type: 'Polygon',
64912                             coordinates: coords
64913                           });
64914                         } else if (geotypes[i] === 'Track' || geotypes[i] === 'gx:Track') {
64915                           var track = gxCoords(geomNode);
64916                           geoms.push({
64917                             type: 'LineString',
64918                             coordinates: track.coords
64919                           });
64920                           if (track.times.length) coordTimes.push(track.times);
64921                         }
64922                       }
64923                     }
64924                   }
64925
64926                   return {
64927                     geoms: geoms,
64928                     coordTimes: coordTimes
64929                   };
64930                 }
64931
64932                 function getPlacemark(root) {
64933                   var geomsAndTimes = getGeometry(root),
64934                       i,
64935                       properties = {},
64936                       name = nodeVal(get1(root, 'name')),
64937                       address = nodeVal(get1(root, 'address')),
64938                       styleUrl = nodeVal(get1(root, 'styleUrl')),
64939                       description = nodeVal(get1(root, 'description')),
64940                       timeSpan = get1(root, 'TimeSpan'),
64941                       timeStamp = get1(root, 'TimeStamp'),
64942                       extendedData = get1(root, 'ExtendedData'),
64943                       lineStyle = get1(root, 'LineStyle'),
64944                       polyStyle = get1(root, 'PolyStyle'),
64945                       visibility = get1(root, 'visibility');
64946                   if (!geomsAndTimes.geoms.length) return [];
64947                   if (name) properties.name = name;
64948                   if (address) properties.address = address;
64949
64950                   if (styleUrl) {
64951                     if (styleUrl[0] !== '#') {
64952                       styleUrl = '#' + styleUrl;
64953                     }
64954
64955                     properties.styleUrl = styleUrl;
64956
64957                     if (styleIndex[styleUrl]) {
64958                       properties.styleHash = styleIndex[styleUrl];
64959                     }
64960
64961                     if (styleMapIndex[styleUrl]) {
64962                       properties.styleMapHash = styleMapIndex[styleUrl];
64963                       properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
64964                     } // Try to populate the lineStyle or polyStyle since we got the style hash
64965
64966
64967                     var style = styleByHash[properties.styleHash];
64968
64969                     if (style) {
64970                       if (!lineStyle) lineStyle = get1(style, 'LineStyle');
64971                       if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
64972                     }
64973                   }
64974
64975                   if (description) properties.description = description;
64976
64977                   if (timeSpan) {
64978                     var begin = nodeVal(get1(timeSpan, 'begin'));
64979                     var end = nodeVal(get1(timeSpan, 'end'));
64980                     properties.timespan = {
64981                       begin: begin,
64982                       end: end
64983                     };
64984                   }
64985
64986                   if (timeStamp) {
64987                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
64988                   }
64989
64990                   if (lineStyle) {
64991                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
64992                         color = linestyles[0],
64993                         opacity = linestyles[1],
64994                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
64995                     if (color) properties.stroke = color;
64996                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
64997                     if (!isNaN(width)) properties['stroke-width'] = width;
64998                   }
64999
65000                   if (polyStyle) {
65001                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
65002                         pcolor = polystyles[0],
65003                         popacity = polystyles[1],
65004                         fill = nodeVal(get1(polyStyle, 'fill')),
65005                         outline = nodeVal(get1(polyStyle, 'outline'));
65006                     if (pcolor) properties.fill = pcolor;
65007                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
65008                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
65009                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
65010                   }
65011
65012                   if (extendedData) {
65013                     var datas = get(extendedData, 'Data'),
65014                         simpleDatas = get(extendedData, 'SimpleData');
65015
65016                     for (i = 0; i < datas.length; i++) {
65017                       properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
65018                     }
65019
65020                     for (i = 0; i < simpleDatas.length; i++) {
65021                       properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
65022                     }
65023                   }
65024
65025                   if (visibility) {
65026                     properties.visibility = nodeVal(visibility);
65027                   }
65028
65029                   if (geomsAndTimes.coordTimes.length) {
65030                     properties.coordTimes = geomsAndTimes.coordTimes.length === 1 ? geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
65031                   }
65032
65033                   var feature = {
65034                     type: 'Feature',
65035                     geometry: geomsAndTimes.geoms.length === 1 ? geomsAndTimes.geoms[0] : {
65036                       type: 'GeometryCollection',
65037                       geometries: geomsAndTimes.geoms
65038                     },
65039                     properties: properties
65040                   };
65041                   if (attr(root, 'id')) feature.id = attr(root, 'id');
65042                   return [feature];
65043                 }
65044
65045                 return gj;
65046               },
65047               gpx: function gpx(doc) {
65048                 var i,
65049                     tracks = get(doc, 'trk'),
65050                     routes = get(doc, 'rte'),
65051                     waypoints = get(doc, 'wpt'),
65052                     // a feature collection
65053                 gj = fc(),
65054                     feature;
65055
65056                 for (i = 0; i < tracks.length; i++) {
65057                   feature = getTrack(tracks[i]);
65058                   if (feature) gj.features.push(feature);
65059                 }
65060
65061                 for (i = 0; i < routes.length; i++) {
65062                   feature = getRoute(routes[i]);
65063                   if (feature) gj.features.push(feature);
65064                 }
65065
65066                 for (i = 0; i < waypoints.length; i++) {
65067                   gj.features.push(getPoint(waypoints[i]));
65068                 }
65069
65070                 function getPoints(node, pointname) {
65071                   var pts = get(node, pointname),
65072                       line = [],
65073                       times = [],
65074                       heartRates = [],
65075                       l = pts.length;
65076                   if (l < 2) return {}; // Invalid line in GeoJSON
65077
65078                   for (var i = 0; i < l; i++) {
65079                     var c = coordPair(pts[i]);
65080                     line.push(c.coordinates);
65081                     if (c.time) times.push(c.time);
65082                     if (c.heartRate) heartRates.push(c.heartRate);
65083                   }
65084
65085                   return {
65086                     line: line,
65087                     times: times,
65088                     heartRates: heartRates
65089                   };
65090                 }
65091
65092                 function getTrack(node) {
65093                   var segments = get(node, 'trkseg'),
65094                       track = [],
65095                       times = [],
65096                       heartRates = [],
65097                       line;
65098
65099                   for (var i = 0; i < segments.length; i++) {
65100                     line = getPoints(segments[i], 'trkpt');
65101
65102                     if (line) {
65103                       if (line.line) track.push(line.line);
65104                       if (line.times && line.times.length) times.push(line.times);
65105                       if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
65106                     }
65107                   }
65108
65109                   if (track.length === 0) return;
65110                   var properties = getProperties(node);
65111                   extend(properties, getLineStyle(get1(node, 'extensions')));
65112                   if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
65113                   if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
65114                   return {
65115                     type: 'Feature',
65116                     properties: properties,
65117                     geometry: {
65118                       type: track.length === 1 ? 'LineString' : 'MultiLineString',
65119                       coordinates: track.length === 1 ? track[0] : track
65120                     }
65121                   };
65122                 }
65123
65124                 function getRoute(node) {
65125                   var line = getPoints(node, 'rtept');
65126                   if (!line.line) return;
65127                   var prop = getProperties(node);
65128                   extend(prop, getLineStyle(get1(node, 'extensions')));
65129                   var routeObj = {
65130                     type: 'Feature',
65131                     properties: prop,
65132                     geometry: {
65133                       type: 'LineString',
65134                       coordinates: line.line
65135                     }
65136                   };
65137                   return routeObj;
65138                 }
65139
65140                 function getPoint(node) {
65141                   var prop = getProperties(node);
65142                   extend(prop, getMulti(node, ['sym']));
65143                   return {
65144                     type: 'Feature',
65145                     properties: prop,
65146                     geometry: {
65147                       type: 'Point',
65148                       coordinates: coordPair(node).coordinates
65149                     }
65150                   };
65151                 }
65152
65153                 function getLineStyle(extensions) {
65154                   var style = {};
65155
65156                   if (extensions) {
65157                     var lineStyle = get1(extensions, 'line');
65158
65159                     if (lineStyle) {
65160                       var color = nodeVal(get1(lineStyle, 'color')),
65161                           opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
65162                           width = parseFloat(nodeVal(get1(lineStyle, 'width')));
65163                       if (color) style.stroke = color;
65164                       if (!isNaN(opacity)) style['stroke-opacity'] = opacity; // GPX width is in mm, convert to px with 96 px per inch
65165
65166                       if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
65167                     }
65168                   }
65169
65170                   return style;
65171                 }
65172
65173                 function getProperties(node) {
65174                   var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
65175                       links = get(node, 'link');
65176                   if (links.length) prop.links = [];
65177
65178                   for (var i = 0, link; i < links.length; i++) {
65179                     link = {
65180                       href: attr(links[i], 'href')
65181                     };
65182                     extend(link, getMulti(links[i], ['text', 'type']));
65183                     prop.links.push(link);
65184                   }
65185
65186                   return prop;
65187                 }
65188
65189                 return gj;
65190               }
65191             };
65192             return t;
65193           }();
65194
65195           module.exports = toGeoJSON;
65196         });
65197
65198         var _initialized = false;
65199         var _enabled = false;
65200
65201         var _geojson;
65202
65203         function svgData(projection, context, dispatch) {
65204           var throttledRedraw = throttle(function () {
65205             dispatch.call('change');
65206           }, 1000);
65207
65208           var _showLabels = true;
65209           var detected = utilDetect();
65210           var layer = select(null);
65211
65212           var _vtService;
65213
65214           var _fileList;
65215
65216           var _template;
65217
65218           var _src;
65219
65220           function init() {
65221             if (_initialized) return; // run once
65222
65223             _geojson = {};
65224             _enabled = true;
65225
65226             function over(d3_event) {
65227               d3_event.stopPropagation();
65228               d3_event.preventDefault();
65229               d3_event.dataTransfer.dropEffect = 'copy';
65230             }
65231
65232             context.container().attr('dropzone', 'copy').on('drop.svgData', function (d3_event) {
65233               d3_event.stopPropagation();
65234               d3_event.preventDefault();
65235               if (!detected.filedrop) return;
65236               drawData.fileList(d3_event.dataTransfer.files);
65237             }).on('dragenter.svgData', over).on('dragexit.svgData', over).on('dragover.svgData', over);
65238             _initialized = true;
65239           }
65240
65241           function getService() {
65242             if (services.vectorTile && !_vtService) {
65243               _vtService = services.vectorTile;
65244
65245               _vtService.event.on('loadedData', throttledRedraw);
65246             } else if (!services.vectorTile && _vtService) {
65247               _vtService = null;
65248             }
65249
65250             return _vtService;
65251           }
65252
65253           function showLayer() {
65254             layerOn();
65255             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
65256               dispatch.call('change');
65257             });
65258           }
65259
65260           function hideLayer() {
65261             throttledRedraw.cancel();
65262             layer.transition().duration(250).style('opacity', 0).on('end', layerOff);
65263           }
65264
65265           function layerOn() {
65266             layer.style('display', 'block');
65267           }
65268
65269           function layerOff() {
65270             layer.selectAll('.viewfield-group').remove();
65271             layer.style('display', 'none');
65272           } // ensure that all geojson features in a collection have IDs
65273
65274
65275           function ensureIDs(gj) {
65276             if (!gj) return null;
65277
65278             if (gj.type === 'FeatureCollection') {
65279               for (var i = 0; i < gj.features.length; i++) {
65280                 ensureFeatureID(gj.features[i]);
65281               }
65282             } else {
65283               ensureFeatureID(gj);
65284             }
65285
65286             return gj;
65287           } // ensure that each single Feature object has a unique ID
65288
65289
65290           function ensureFeatureID(feature) {
65291             if (!feature) return;
65292             feature.__featurehash__ = utilHashcode(fastJsonStableStringify(feature));
65293             return feature;
65294           } // Prefer an array of Features instead of a FeatureCollection
65295
65296
65297           function getFeatures(gj) {
65298             if (!gj) return [];
65299
65300             if (gj.type === 'FeatureCollection') {
65301               return gj.features;
65302             } else {
65303               return [gj];
65304             }
65305           }
65306
65307           function featureKey(d) {
65308             return d.__featurehash__;
65309           }
65310
65311           function isPolygon(d) {
65312             return d.geometry.type === 'Polygon' || d.geometry.type === 'MultiPolygon';
65313           }
65314
65315           function clipPathID(d) {
65316             return 'ideditor-data-' + d.__featurehash__ + '-clippath';
65317           }
65318
65319           function featureClasses(d) {
65320             return ['data' + d.__featurehash__, d.geometry.type, isPolygon(d) ? 'area' : '', d.__layerID__ || ''].filter(Boolean).join(' ');
65321           }
65322
65323           function drawData(selection) {
65324             var vtService = getService();
65325             var getPath = svgPath(projection).geojson;
65326             var getAreaPath = svgPath(projection, null, true).geojson;
65327             var hasData = drawData.hasData();
65328             layer = selection.selectAll('.layer-mapdata').data(_enabled && hasData ? [0] : []);
65329             layer.exit().remove();
65330             layer = layer.enter().append('g').attr('class', 'layer-mapdata').merge(layer);
65331             var surface = context.surface();
65332             if (!surface || surface.empty()) return; // not ready to draw yet, starting up
65333             // Gather data
65334
65335             var geoData, polygonData;
65336
65337             if (_template && vtService) {
65338               // fetch data from vector tile service
65339               var sourceID = _template;
65340               vtService.loadTiles(sourceID, _template, projection);
65341               geoData = vtService.data(sourceID, projection);
65342             } else {
65343               geoData = getFeatures(_geojson);
65344             }
65345
65346             geoData = geoData.filter(getPath);
65347             polygonData = geoData.filter(isPolygon); // Draw clip paths for polygons
65348
65349             var clipPaths = surface.selectAll('defs').selectAll('.clipPath-data').data(polygonData, featureKey);
65350             clipPaths.exit().remove();
65351             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-data').attr('id', clipPathID);
65352             clipPathsEnter.append('path');
65353             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', getAreaPath); // Draw fill, shadow, stroke layers
65354
65355             var datagroups = layer.selectAll('g.datagroup').data(['fill', 'shadow', 'stroke']);
65356             datagroups = datagroups.enter().append('g').attr('class', function (d) {
65357               return 'datagroup datagroup-' + d;
65358             }).merge(datagroups); // Draw paths
65359
65360             var pathData = {
65361               fill: polygonData,
65362               shadow: geoData,
65363               stroke: geoData
65364             };
65365             var paths = datagroups.selectAll('path').data(function (layer) {
65366               return pathData[layer];
65367             }, featureKey); // exit
65368
65369             paths.exit().remove(); // enter/update
65370
65371             paths = paths.enter().append('path').attr('class', function (d) {
65372               var datagroup = this.parentNode.__data__;
65373               return 'pathdata ' + datagroup + ' ' + featureClasses(d);
65374             }).attr('clip-path', function (d) {
65375               var datagroup = this.parentNode.__data__;
65376               return datagroup === 'fill' ? 'url(#' + clipPathID(d) + ')' : null;
65377             }).merge(paths).attr('d', function (d) {
65378               var datagroup = this.parentNode.__data__;
65379               return datagroup === 'fill' ? getAreaPath(d) : getPath(d);
65380             }); // Draw labels
65381
65382             layer.call(drawLabels, 'label-halo', geoData).call(drawLabels, 'label', geoData);
65383
65384             function drawLabels(selection, textClass, data) {
65385               var labelPath = d3_geoPath(projection);
65386               var labelData = data.filter(function (d) {
65387                 return _showLabels && d.properties && (d.properties.desc || d.properties.name);
65388               });
65389               var labels = selection.selectAll('text.' + textClass).data(labelData, featureKey); // exit
65390
65391               labels.exit().remove(); // enter/update
65392
65393               labels = labels.enter().append('text').attr('class', function (d) {
65394                 return textClass + ' ' + featureClasses(d);
65395               }).merge(labels).text(function (d) {
65396                 return d.properties.desc || d.properties.name;
65397               }).attr('x', function (d) {
65398                 var centroid = labelPath.centroid(d);
65399                 return centroid[0] + 11;
65400               }).attr('y', function (d) {
65401                 var centroid = labelPath.centroid(d);
65402                 return centroid[1];
65403               });
65404             }
65405           }
65406
65407           function getExtension(fileName) {
65408             if (!fileName) return;
65409             var re = /\.(gpx|kml|(geo)?json)$/i;
65410             var match = fileName.toLowerCase().match(re);
65411             return match && match.length && match[0];
65412           }
65413
65414           function xmlToDom(textdata) {
65415             return new DOMParser().parseFromString(textdata, 'text/xml');
65416           }
65417
65418           drawData.setFile = function (extension, data) {
65419             _template = null;
65420             _fileList = null;
65421             _geojson = null;
65422             _src = null;
65423             var gj;
65424
65425             switch (extension) {
65426               case '.gpx':
65427                 gj = togeojson.gpx(xmlToDom(data));
65428                 break;
65429
65430               case '.kml':
65431                 gj = togeojson.kml(xmlToDom(data));
65432                 break;
65433
65434               case '.geojson':
65435               case '.json':
65436                 gj = JSON.parse(data);
65437                 break;
65438             }
65439
65440             gj = gj || {};
65441
65442             if (Object.keys(gj).length) {
65443               _geojson = ensureIDs(gj);
65444               _src = extension + ' data file';
65445               this.fitZoom();
65446             }
65447
65448             dispatch.call('change');
65449             return this;
65450           };
65451
65452           drawData.showLabels = function (val) {
65453             if (!arguments.length) return _showLabels;
65454             _showLabels = val;
65455             return this;
65456           };
65457
65458           drawData.enabled = function (val) {
65459             if (!arguments.length) return _enabled;
65460             _enabled = val;
65461
65462             if (_enabled) {
65463               showLayer();
65464             } else {
65465               hideLayer();
65466             }
65467
65468             dispatch.call('change');
65469             return this;
65470           };
65471
65472           drawData.hasData = function () {
65473             var gj = _geojson || {};
65474             return !!(_template || Object.keys(gj).length);
65475           };
65476
65477           drawData.template = function (val, src) {
65478             if (!arguments.length) return _template; // test source against OSM imagery blocklists..
65479
65480             var osm = context.connection();
65481
65482             if (osm) {
65483               var blocklists = osm.imageryBlocklists();
65484               var fail = false;
65485               var tested = 0;
65486               var regex;
65487
65488               for (var i = 0; i < blocklists.length; i++) {
65489                 regex = blocklists[i];
65490                 fail = regex.test(val);
65491                 tested++;
65492                 if (fail) break;
65493               } // ensure at least one test was run.
65494
65495
65496               if (!tested) {
65497                 regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
65498                 fail = regex.test(val);
65499               }
65500             }
65501
65502             _template = val;
65503             _fileList = null;
65504             _geojson = null; // strip off the querystring/hash from the template,
65505             // it often includes the access token
65506
65507             _src = src || 'vectortile:' + val.split(/[?#]/)[0];
65508             dispatch.call('change');
65509             return this;
65510           };
65511
65512           drawData.geojson = function (gj, src) {
65513             if (!arguments.length) return _geojson;
65514             _template = null;
65515             _fileList = null;
65516             _geojson = null;
65517             _src = null;
65518             gj = gj || {};
65519
65520             if (Object.keys(gj).length) {
65521               _geojson = ensureIDs(gj);
65522               _src = src || 'unknown.geojson';
65523             }
65524
65525             dispatch.call('change');
65526             return this;
65527           };
65528
65529           drawData.fileList = function (fileList) {
65530             if (!arguments.length) return _fileList;
65531             _template = null;
65532             _fileList = fileList;
65533             _geojson = null;
65534             _src = null;
65535             if (!fileList || !fileList.length) return this;
65536             var f = fileList[0];
65537             var extension = getExtension(f.name);
65538             var reader = new FileReader();
65539
65540             reader.onload = function () {
65541               return function (e) {
65542                 drawData.setFile(extension, e.target.result);
65543               };
65544             }();
65545
65546             reader.readAsText(f);
65547             return this;
65548           };
65549
65550           drawData.url = function (url, defaultExtension) {
65551             _template = null;
65552             _fileList = null;
65553             _geojson = null;
65554             _src = null; // strip off any querystring/hash from the url before checking extension
65555
65556             var testUrl = url.split(/[?#]/)[0];
65557             var extension = getExtension(testUrl) || defaultExtension;
65558
65559             if (extension) {
65560               _template = null;
65561               d3_text(url).then(function (data) {
65562                 drawData.setFile(extension, data);
65563               })["catch"](function () {
65564                 /* ignore */
65565               });
65566             } else {
65567               drawData.template(url);
65568             }
65569
65570             return this;
65571           };
65572
65573           drawData.getSrc = function () {
65574             return _src || '';
65575           };
65576
65577           drawData.fitZoom = function () {
65578             var features = getFeatures(_geojson);
65579             if (!features.length) return;
65580             var map = context.map();
65581             var viewport = map.trimmedExtent().polygon();
65582             var coords = features.reduce(function (coords, feature) {
65583               var geom = feature.geometry;
65584               if (!geom) return coords;
65585               var c = geom.coordinates;
65586               /* eslint-disable no-fallthrough */
65587
65588               switch (geom.type) {
65589                 case 'Point':
65590                   c = [c];
65591
65592                 case 'MultiPoint':
65593                 case 'LineString':
65594                   break;
65595
65596                 case 'MultiPolygon':
65597                   c = utilArrayFlatten(c);
65598
65599                 case 'Polygon':
65600                 case 'MultiLineString':
65601                   c = utilArrayFlatten(c);
65602                   break;
65603               }
65604               /* eslint-enable no-fallthrough */
65605
65606
65607               return utilArrayUnion(coords, c);
65608             }, []);
65609
65610             if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
65611               var extent = geoExtent(d3_geoBounds({
65612                 type: 'LineString',
65613                 coordinates: coords
65614               }));
65615               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
65616             }
65617
65618             return this;
65619           };
65620
65621           init();
65622           return drawData;
65623         }
65624
65625         function svgDebug(projection, context) {
65626           function drawDebug(selection) {
65627             var showTile = context.getDebug('tile');
65628             var showCollision = context.getDebug('collision');
65629             var showImagery = context.getDebug('imagery');
65630             var showTouchTargets = context.getDebug('target');
65631             var showDownloaded = context.getDebug('downloaded');
65632             var debugData = [];
65633
65634             if (showTile) {
65635               debugData.push({
65636                 "class": 'red',
65637                 label: 'tile'
65638               });
65639             }
65640
65641             if (showCollision) {
65642               debugData.push({
65643                 "class": 'yellow',
65644                 label: 'collision'
65645               });
65646             }
65647
65648             if (showImagery) {
65649               debugData.push({
65650                 "class": 'orange',
65651                 label: 'imagery'
65652               });
65653             }
65654
65655             if (showTouchTargets) {
65656               debugData.push({
65657                 "class": 'pink',
65658                 label: 'touchTargets'
65659               });
65660             }
65661
65662             if (showDownloaded) {
65663               debugData.push({
65664                 "class": 'purple',
65665                 label: 'downloaded'
65666               });
65667             }
65668
65669             var legend = context.container().select('.main-content').selectAll('.debug-legend').data(debugData.length ? [0] : []);
65670             legend.exit().remove();
65671             legend = legend.enter().append('div').attr('class', 'fillD debug-legend').merge(legend);
65672             var legendItems = legend.selectAll('.debug-legend-item').data(debugData, function (d) {
65673               return d.label;
65674             });
65675             legendItems.exit().remove();
65676             legendItems.enter().append('span').attr('class', function (d) {
65677               return "debug-legend-item ".concat(d["class"]);
65678             }).text(function (d) {
65679               return d.label;
65680             });
65681             var layer = selection.selectAll('.layer-debug').data(showImagery || showDownloaded ? [0] : []);
65682             layer.exit().remove();
65683             layer = layer.enter().append('g').attr('class', 'layer-debug').merge(layer); // imagery
65684
65685             var extent = context.map().extent();
65686             _mainFileFetcher.get('imagery').then(function (d) {
65687               var hits = showImagery && d.query.bbox(extent.rectangle(), true) || [];
65688               var features = hits.map(function (d) {
65689                 return d.features[d.id];
65690               });
65691               var imagery = layer.selectAll('path.debug-imagery').data(features);
65692               imagery.exit().remove();
65693               imagery.enter().append('path').attr('class', 'debug-imagery debug orange');
65694             })["catch"](function () {
65695               /* ignore */
65696             }); // downloaded
65697
65698             var osm = context.connection();
65699             var dataDownloaded = [];
65700
65701             if (osm && showDownloaded) {
65702               var rtree = osm.caches('get').tile.rtree;
65703               dataDownloaded = rtree.all().map(function (bbox) {
65704                 return {
65705                   type: 'Feature',
65706                   properties: {
65707                     id: bbox.id
65708                   },
65709                   geometry: {
65710                     type: 'Polygon',
65711                     coordinates: [[[bbox.minX, bbox.minY], [bbox.minX, bbox.maxY], [bbox.maxX, bbox.maxY], [bbox.maxX, bbox.minY], [bbox.minX, bbox.minY]]]
65712                   }
65713                 };
65714               });
65715             }
65716
65717             var downloaded = layer.selectAll('path.debug-downloaded').data(showDownloaded ? dataDownloaded : []);
65718             downloaded.exit().remove();
65719             downloaded.enter().append('path').attr('class', 'debug-downloaded debug purple'); // update
65720
65721             layer.selectAll('path').attr('d', svgPath(projection).geojson);
65722           } // This looks strange because `enabled` methods on other layers are
65723           // chainable getter/setters, and this one is just a getter.
65724
65725
65726           drawDebug.enabled = function () {
65727             if (!arguments.length) {
65728               return context.getDebug('tile') || context.getDebug('collision') || context.getDebug('imagery') || context.getDebug('target') || context.getDebug('downloaded');
65729             } else {
65730               return this;
65731             }
65732           };
65733
65734           return drawDebug;
65735         }
65736
65737         /*
65738             A standalone SVG element that contains only a `defs` sub-element. To be
65739             used once globally, since defs IDs must be unique within a document.
65740         */
65741
65742         function svgDefs(context) {
65743           var _defsSelection = select(null);
65744
65745           var _spritesheetIds = ['iD-sprite', 'maki-sprite', 'temaki-sprite', 'fa-sprite', 'community-sprite'];
65746
65747           function drawDefs(selection) {
65748             _defsSelection = selection.append('defs'); // add markers
65749
65750             _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'); // SVG markers have to be given a colour where they're defined
65751             // (they can't inherit it from the line they're attached to),
65752             // so we need to manually define markers for each color of tag
65753             // (also, it's slightly nicer if we can control the
65754             // positioning for different tags)
65755
65756
65757             function addSidedMarker(name, color, offset) {
65758               _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', color);
65759             }
65760
65761             addSidedMarker('natural', 'rgb(170, 170, 170)', 0); // for a coastline, the arrows are (somewhat unintuitively) on
65762             // the water side, so let's color them blue (with a gap) to
65763             // give a stronger indication
65764
65765             addSidedMarker('coastline', '#77dede', 1);
65766             addSidedMarker('waterway', '#77dede', 1); // barriers have a dashed line, and separating the triangle
65767             // from the line visually suits that
65768
65769             addSidedMarker('barrier', '#ddd', 1);
65770             addSidedMarker('man_made', '#fff', 0);
65771
65772             _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');
65773
65774             _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'); // add patterns
65775
65776
65777             var patterns = _defsSelection.selectAll('pattern').data([// pattern name, pattern image name
65778             ['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) {
65779               return 'ideditor-pattern-' + d[0];
65780             }).attr('width', 32).attr('height', 32).attr('patternUnits', 'userSpaceOnUse');
65781
65782             patterns.append('rect').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('class', function (d) {
65783               return 'pattern-color-' + d[0];
65784             });
65785             patterns.append('image').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('xlink:href', function (d) {
65786               return context.imagePath('pattern/' + d[1] + '.png');
65787             }); // add clip paths
65788
65789             _defsSelection.selectAll('clipPath').data([12, 18, 20, 32, 45]).enter().append('clipPath').attr('id', function (d) {
65790               return 'ideditor-clip-square-' + d;
65791             }).append('rect').attr('x', 0).attr('y', 0).attr('width', function (d) {
65792               return d;
65793             }).attr('height', function (d) {
65794               return d;
65795             }); // add symbol spritesheets
65796
65797
65798             addSprites(_spritesheetIds, true);
65799           }
65800
65801           function addSprites(ids, overrideColors) {
65802             _spritesheetIds = utilArrayUniq(_spritesheetIds.concat(ids));
65803
65804             var spritesheets = _defsSelection.selectAll('.spritesheet').data(_spritesheetIds);
65805
65806             spritesheets.enter().append('g').attr('class', function (d) {
65807               return 'spritesheet spritesheet-' + d;
65808             }).each(function (d) {
65809               var url = context.imagePath(d + '.svg');
65810               var node = select(this).node();
65811               svg(url).then(function (svg) {
65812                 node.appendChild(select(svg.documentElement).attr('id', 'ideditor-' + d).node());
65813
65814                 if (overrideColors && d !== 'iD-sprite') {
65815                   // allow icon colors to be overridden..
65816                   select(node).selectAll('path').attr('fill', 'currentColor');
65817                 }
65818               })["catch"](function () {
65819                 /* ignore */
65820               });
65821             });
65822             spritesheets.exit().remove();
65823           }
65824
65825           drawDefs.addSprites = addSprites;
65826           return drawDefs;
65827         }
65828
65829         var _layerEnabled$2 = false;
65830
65831         var _qaService$2;
65832
65833         function svgKeepRight(projection, context, dispatch) {
65834           var throttledRedraw = throttle(function () {
65835             return dispatch.call('change');
65836           }, 1000);
65837
65838           var minZoom = 12;
65839           var touchLayer = select(null);
65840           var drawLayer = select(null);
65841           var layerVisible = false;
65842
65843           function markerPath(selection, klass) {
65844             selection.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');
65845           } // Loosely-coupled keepRight service for fetching issues.
65846
65847
65848           function getService() {
65849             if (services.keepRight && !_qaService$2) {
65850               _qaService$2 = services.keepRight;
65851
65852               _qaService$2.on('loaded', throttledRedraw);
65853             } else if (!services.keepRight && _qaService$2) {
65854               _qaService$2 = null;
65855             }
65856
65857             return _qaService$2;
65858           } // Show the markers
65859
65860
65861           function editOn() {
65862             if (!layerVisible) {
65863               layerVisible = true;
65864               drawLayer.style('display', 'block');
65865             }
65866           } // Immediately remove the markers and their touch targets
65867
65868
65869           function editOff() {
65870             if (layerVisible) {
65871               layerVisible = false;
65872               drawLayer.style('display', 'none');
65873               drawLayer.selectAll('.qaItem.keepRight').remove();
65874               touchLayer.selectAll('.qaItem.keepRight').remove();
65875             }
65876           } // Enable the layer.  This shows the markers and transitions them to visible.
65877
65878
65879           function layerOn() {
65880             editOn();
65881             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
65882               return dispatch.call('change');
65883             });
65884           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
65885
65886
65887           function layerOff() {
65888             throttledRedraw.cancel();
65889             drawLayer.interrupt();
65890             touchLayer.selectAll('.qaItem.keepRight').remove();
65891             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
65892               editOff();
65893               dispatch.call('change');
65894             });
65895           } // Update the issue markers
65896
65897
65898           function updateMarkers() {
65899             if (!layerVisible || !_layerEnabled$2) return;
65900             var service = getService();
65901             var selectedID = context.selectedErrorID();
65902             var data = service ? service.getItems(projection) : [];
65903             var getTransform = svgPointTransform(projection); // Draw markers..
65904
65905             var markers = drawLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
65906               return d.id;
65907             }); // exit
65908
65909             markers.exit().remove(); // enter
65910
65911             var markersEnter = markers.enter().append('g').attr('class', function (d) {
65912               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
65913             });
65914             markersEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
65915             markersEnter.append('path').call(markerPath, 'shadow');
65916             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'); // update
65917
65918             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
65919               return d.id === selectedID;
65920             }).attr('transform', getTransform); // Draw targets..
65921
65922             if (touchLayer.empty()) return;
65923             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
65924             var targets = touchLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
65925               return d.id;
65926             }); // exit
65927
65928             targets.exit().remove(); // enter/update
65929
65930             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
65931               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
65932             }).attr('transform', getTransform);
65933
65934             function sortY(a, b) {
65935               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];
65936             }
65937           } // Draw the keepRight layer and schedule loading issues and updating markers.
65938
65939
65940           function drawKeepRight(selection) {
65941             var service = getService();
65942             var surface = context.surface();
65943
65944             if (surface && !surface.empty()) {
65945               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
65946             }
65947
65948             drawLayer = selection.selectAll('.layer-keepRight').data(service ? [0] : []);
65949             drawLayer.exit().remove();
65950             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-keepRight').style('display', _layerEnabled$2 ? 'block' : 'none').merge(drawLayer);
65951
65952             if (_layerEnabled$2) {
65953               if (service && ~~context.map().zoom() >= minZoom) {
65954                 editOn();
65955                 service.loadIssues(projection);
65956                 updateMarkers();
65957               } else {
65958                 editOff();
65959               }
65960             }
65961           } // Toggles the layer on and off
65962
65963
65964           drawKeepRight.enabled = function (val) {
65965             if (!arguments.length) return _layerEnabled$2;
65966             _layerEnabled$2 = val;
65967
65968             if (_layerEnabled$2) {
65969               layerOn();
65970             } else {
65971               layerOff();
65972
65973               if (context.selectedErrorID()) {
65974                 context.enter(modeBrowse(context));
65975               }
65976             }
65977
65978             dispatch.call('change');
65979             return this;
65980           };
65981
65982           drawKeepRight.supported = function () {
65983             return !!getService();
65984           };
65985
65986           return drawKeepRight;
65987         }
65988
65989         function svgGeolocate(projection) {
65990           var layer = select(null);
65991
65992           var _position;
65993
65994           function init() {
65995             if (svgGeolocate.initialized) return; // run once
65996
65997             svgGeolocate.enabled = false;
65998             svgGeolocate.initialized = true;
65999           }
66000
66001           function showLayer() {
66002             layer.style('display', 'block');
66003           }
66004
66005           function hideLayer() {
66006             layer.transition().duration(250).style('opacity', 0);
66007           }
66008
66009           function layerOn() {
66010             layer.style('opacity', 0).transition().duration(250).style('opacity', 1);
66011           }
66012
66013           function layerOff() {
66014             layer.style('display', 'none');
66015           }
66016
66017           function transform(d) {
66018             return svgPointTransform(projection)(d);
66019           }
66020
66021           function accuracy(accuracy, loc) {
66022             // converts accuracy to pixels...
66023             var degreesRadius = geoMetersToLat(accuracy),
66024                 tangentLoc = [loc[0], loc[1] + degreesRadius],
66025                 projectedTangent = projection(tangentLoc),
66026                 projectedLoc = projection([loc[0], loc[1]]); // southern most point will have higher pixel value...
66027
66028             return Math.round(projectedLoc[1] - projectedTangent[1]).toString();
66029           }
66030
66031           function update() {
66032             var geolocation = {
66033               loc: [_position.coords.longitude, _position.coords.latitude]
66034             };
66035             var groups = layer.selectAll('.geolocations').selectAll('.geolocation').data([geolocation]);
66036             groups.exit().remove();
66037             var pointsEnter = groups.enter().append('g').attr('class', 'geolocation');
66038             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');
66039             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');
66040             groups.merge(pointsEnter).attr('transform', transform);
66041             layer.select('.geolocate-radius').attr('r', accuracy(_position.coords.accuracy, geolocation.loc));
66042           }
66043
66044           function drawLocation(selection) {
66045             var enabled = svgGeolocate.enabled;
66046             layer = selection.selectAll('.layer-geolocate').data([0]);
66047             layer.exit().remove();
66048             var layerEnter = layer.enter().append('g').attr('class', 'layer-geolocate').style('display', enabled ? 'block' : 'none');
66049             layerEnter.append('g').attr('class', 'geolocations');
66050             layer = layerEnter.merge(layer);
66051
66052             if (enabled) {
66053               update();
66054             } else {
66055               layerOff();
66056             }
66057           }
66058
66059           drawLocation.enabled = function (position, enabled) {
66060             if (!arguments.length) return svgGeolocate.enabled;
66061             _position = position;
66062             svgGeolocate.enabled = enabled;
66063
66064             if (svgGeolocate.enabled) {
66065               showLayer();
66066               layerOn();
66067             } else {
66068               hideLayer();
66069             }
66070
66071             return this;
66072           };
66073
66074           init();
66075           return drawLocation;
66076         }
66077
66078         function svgLabels(projection, context) {
66079           var path = d3_geoPath(projection);
66080           var detected = utilDetect();
66081           var baselineHack = detected.ie || detected.browser.toLowerCase() === 'edge' || detected.browser.toLowerCase() === 'firefox' && detected.version >= 70;
66082
66083           var _rdrawn = new RBush();
66084
66085           var _rskipped = new RBush();
66086
66087           var _textWidthCache = {};
66088           var _entitybboxes = {}; // Listed from highest to lowest priority
66089
66090           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', 'name', '*', 12], ['area', 'name', '*', 12], ['point', 'name', '*', 10]];
66091
66092           function shouldSkipIcon(preset) {
66093             var noIcons = ['building', 'landuse', 'natural'];
66094             return noIcons.some(function (s) {
66095               return preset.id.indexOf(s) >= 0;
66096             });
66097           }
66098
66099           function get(array, prop) {
66100             return function (d, i) {
66101               return array[i][prop];
66102             };
66103           }
66104
66105           function textWidth(text, size, elem) {
66106             var c = _textWidthCache[size];
66107             if (!c) c = _textWidthCache[size] = {};
66108
66109             if (c[text]) {
66110               return c[text];
66111             } else if (elem) {
66112               c[text] = elem.getComputedTextLength();
66113               return c[text];
66114             } else {
66115               var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
66116
66117               if (str === null) {
66118                 return size / 3 * 2 * text.length;
66119               } else {
66120                 return size / 3 * (2 * text.length + str.length);
66121               }
66122             }
66123           }
66124
66125           function drawLinePaths(selection, entities, filter, classes, labels) {
66126             var paths = selection.selectAll('path').filter(filter).data(entities, osmEntity.key); // exit
66127
66128             paths.exit().remove(); // enter/update
66129
66130             paths.enter().append('path').style('stroke-width', get(labels, 'font-size')).attr('id', function (d) {
66131               return 'ideditor-labelpath-' + d.id;
66132             }).attr('class', classes).merge(paths).attr('d', get(labels, 'lineString'));
66133           }
66134
66135           function drawLineLabels(selection, entities, filter, classes, labels) {
66136             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
66137
66138             texts.exit().remove(); // enter
66139
66140             texts.enter().append('text').attr('class', function (d, i) {
66141               return classes + ' ' + labels[i].classes + ' ' + d.id;
66142             }).attr('dy', baselineHack ? '0.35em' : null).append('textPath').attr('class', 'textpath'); // update
66143
66144             selection.selectAll('text.' + classes).selectAll('.textpath').filter(filter).data(entities, osmEntity.key).attr('startOffset', '50%').attr('xlink:href', function (d) {
66145               return '#ideditor-labelpath-' + d.id;
66146             }).text(utilDisplayNameForPath);
66147           }
66148
66149           function drawPointLabels(selection, entities, filter, classes, labels) {
66150             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
66151
66152             texts.exit().remove(); // enter/update
66153
66154             texts.enter().append('text').attr('class', function (d, i) {
66155               return classes + ' ' + labels[i].classes + ' ' + d.id;
66156             }).merge(texts).attr('x', get(labels, 'x')).attr('y', get(labels, 'y')).style('text-anchor', get(labels, 'textAnchor')).text(utilDisplayName).each(function (d, i) {
66157               textWidth(utilDisplayName(d), labels[i].height, this);
66158             });
66159           }
66160
66161           function drawAreaLabels(selection, entities, filter, classes, labels) {
66162             entities = entities.filter(hasText);
66163             labels = labels.filter(hasText);
66164             drawPointLabels(selection, entities, filter, classes, labels);
66165
66166             function hasText(d, i) {
66167               return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
66168             }
66169           }
66170
66171           function drawAreaIcons(selection, entities, filter, classes, labels) {
66172             var icons = selection.selectAll('use.' + classes).filter(filter).data(entities, osmEntity.key); // exit
66173
66174             icons.exit().remove(); // enter/update
66175
66176             icons.enter().append('use').attr('class', 'icon ' + classes).attr('width', '17px').attr('height', '17px').merge(icons).attr('transform', get(labels, 'transform')).attr('xlink:href', function (d) {
66177               var preset = _mainPresetIndex.match(d, context.graph());
66178               var picon = preset && preset.icon;
66179
66180               if (!picon) {
66181                 return '';
66182               } else {
66183                 var isMaki = /^maki-/.test(picon);
66184                 return '#' + picon + (isMaki ? '-15' : '');
66185               }
66186             });
66187           }
66188
66189           function drawCollisionBoxes(selection, rtree, which) {
66190             var classes = 'debug ' + which + ' ' + (which === 'debug-skipped' ? 'orange' : 'yellow');
66191             var gj = [];
66192
66193             if (context.getDebug('collision')) {
66194               gj = rtree.all().map(function (d) {
66195                 return {
66196                   type: 'Polygon',
66197                   coordinates: [[[d.minX, d.minY], [d.maxX, d.minY], [d.maxX, d.maxY], [d.minX, d.maxY], [d.minX, d.minY]]]
66198                 };
66199               });
66200             }
66201
66202             var boxes = selection.selectAll('.' + which).data(gj); // exit
66203
66204             boxes.exit().remove(); // enter/update
66205
66206             boxes.enter().append('path').attr('class', classes).merge(boxes).attr('d', d3_geoPath());
66207           }
66208
66209           function drawLabels(selection, graph, entities, filter, dimensions, fullRedraw) {
66210             var wireframe = context.surface().classed('fill-wireframe');
66211             var zoom = geoScaleToZoom(projection.scale());
66212             var labelable = [];
66213             var renderNodeAs = {};
66214             var i, j, k, entity, geometry;
66215
66216             for (i = 0; i < labelStack.length; i++) {
66217               labelable.push([]);
66218             }
66219
66220             if (fullRedraw) {
66221               _rdrawn.clear();
66222
66223               _rskipped.clear();
66224
66225               _entitybboxes = {};
66226             } else {
66227               for (i = 0; i < entities.length; i++) {
66228                 entity = entities[i];
66229                 var toRemove = [].concat(_entitybboxes[entity.id] || []).concat(_entitybboxes[entity.id + 'I'] || []);
66230
66231                 for (j = 0; j < toRemove.length; j++) {
66232                   _rdrawn.remove(toRemove[j]);
66233
66234                   _rskipped.remove(toRemove[j]);
66235                 }
66236               }
66237             } // Loop through all the entities to do some preprocessing
66238
66239
66240             for (i = 0; i < entities.length; i++) {
66241               entity = entities[i];
66242               geometry = entity.geometry(graph); // Insert collision boxes around interesting points/vertices
66243
66244               if (geometry === 'point' || geometry === 'vertex' && isInterestingVertex(entity)) {
66245                 var hasDirections = entity.directions(graph, projection).length;
66246                 var markerPadding;
66247
66248                 if (!wireframe && geometry === 'point' && !(zoom >= 18 && hasDirections)) {
66249                   renderNodeAs[entity.id] = 'point';
66250                   markerPadding = 20; // extra y for marker height
66251                 } else {
66252                   renderNodeAs[entity.id] = 'vertex';
66253                   markerPadding = 0;
66254                 }
66255
66256                 var coord = projection(entity.loc);
66257                 var nodePadding = 10;
66258                 var bbox = {
66259                   minX: coord[0] - nodePadding,
66260                   minY: coord[1] - nodePadding - markerPadding,
66261                   maxX: coord[0] + nodePadding,
66262                   maxY: coord[1] + nodePadding
66263                 };
66264                 doInsert(bbox, entity.id + 'P');
66265               } // From here on, treat vertices like points
66266
66267
66268               if (geometry === 'vertex') {
66269                 geometry = 'point';
66270               } // Determine which entities are label-able
66271
66272
66273               var preset = geometry === 'area' && _mainPresetIndex.match(entity, graph);
66274               var icon = preset && !shouldSkipIcon(preset) && preset.icon;
66275               if (!icon && !utilDisplayName(entity)) continue;
66276
66277               for (k = 0; k < labelStack.length; k++) {
66278                 var matchGeom = labelStack[k][0];
66279                 var matchKey = labelStack[k][1];
66280                 var matchVal = labelStack[k][2];
66281                 var hasVal = entity.tags[matchKey];
66282
66283                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
66284                   labelable[k].push(entity);
66285                   break;
66286                 }
66287               }
66288             }
66289
66290             var positions = {
66291               point: [],
66292               line: [],
66293               area: []
66294             };
66295             var labelled = {
66296               point: [],
66297               line: [],
66298               area: []
66299             }; // Try and find a valid label for labellable entities
66300
66301             for (k = 0; k < labelable.length; k++) {
66302               var fontSize = labelStack[k][3];
66303
66304               for (i = 0; i < labelable[k].length; i++) {
66305                 entity = labelable[k][i];
66306                 geometry = entity.geometry(graph);
66307                 var getName = geometry === 'line' ? utilDisplayNameForPath : utilDisplayName;
66308                 var name = getName(entity);
66309                 var width = name && textWidth(name, fontSize);
66310                 var p = null;
66311
66312                 if (geometry === 'point' || geometry === 'vertex') {
66313                   // no point or vertex labels in wireframe mode
66314                   // no vertex labels at low zooms (vertices have no icons)
66315                   if (wireframe) continue;
66316                   var renderAs = renderNodeAs[entity.id];
66317                   if (renderAs === 'vertex' && zoom < 17) continue;
66318                   p = getPointLabel(entity, width, fontSize, renderAs);
66319                 } else if (geometry === 'line') {
66320                   p = getLineLabel(entity, width, fontSize);
66321                 } else if (geometry === 'area') {
66322                   p = getAreaLabel(entity, width, fontSize);
66323                 }
66324
66325                 if (p) {
66326                   if (geometry === 'vertex') {
66327                     geometry = 'point';
66328                   } // treat vertex like point
66329
66330
66331                   p.classes = geometry + ' tag-' + labelStack[k][1];
66332                   positions[geometry].push(p);
66333                   labelled[geometry].push(entity);
66334                 }
66335               }
66336             }
66337
66338             function isInterestingVertex(entity) {
66339               var selectedIDs = context.selectedIDs();
66340               return entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || selectedIDs.indexOf(entity.id) !== -1 || graph.parentWays(entity).some(function (parent) {
66341                 return selectedIDs.indexOf(parent.id) !== -1;
66342               });
66343             }
66344
66345             function getPointLabel(entity, width, height, geometry) {
66346               var y = geometry === 'point' ? -12 : 0;
66347               var pointOffsets = {
66348                 ltr: [15, y, 'start'],
66349                 rtl: [-15, y, 'end']
66350               };
66351               var textDirection = _mainLocalizer.textDirection();
66352               var coord = projection(entity.loc);
66353               var textPadding = 2;
66354               var offset = pointOffsets[textDirection];
66355               var p = {
66356                 height: height,
66357                 width: width,
66358                 x: coord[0] + offset[0],
66359                 y: coord[1] + offset[1],
66360                 textAnchor: offset[2]
66361               }; // insert a collision box for the text label..
66362
66363               var bbox;
66364
66365               if (textDirection === 'rtl') {
66366                 bbox = {
66367                   minX: p.x - width - textPadding,
66368                   minY: p.y - height / 2 - textPadding,
66369                   maxX: p.x + textPadding,
66370                   maxY: p.y + height / 2 + textPadding
66371                 };
66372               } else {
66373                 bbox = {
66374                   minX: p.x - textPadding,
66375                   minY: p.y - height / 2 - textPadding,
66376                   maxX: p.x + width + textPadding,
66377                   maxY: p.y + height / 2 + textPadding
66378                 };
66379               }
66380
66381               if (tryInsert([bbox], entity.id, true)) {
66382                 return p;
66383               }
66384             }
66385
66386             function getLineLabel(entity, width, height) {
66387               var viewport = geoExtent(context.projection.clipExtent()).polygon();
66388               var points = graph.childNodes(entity).map(function (node) {
66389                 return projection(node.loc);
66390               });
66391               var length = geoPathLength(points);
66392               if (length < width + 20) return; // % along the line to attempt to place the label
66393
66394               var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
66395               var padding = 3;
66396
66397               for (var i = 0; i < lineOffsets.length; i++) {
66398                 var offset = lineOffsets[i];
66399                 var middle = offset / 100 * length;
66400                 var start = middle - width / 2;
66401                 if (start < 0 || start + width > length) continue; // generate subpath and ignore paths that are invalid or don't cross viewport.
66402
66403                 var sub = subpath(points, start, start + width);
66404
66405                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
66406                   continue;
66407                 }
66408
66409                 var isReverse = reverse(sub);
66410
66411                 if (isReverse) {
66412                   sub = sub.reverse();
66413                 }
66414
66415                 var bboxes = [];
66416                 var boxsize = (height + 2) / 2;
66417
66418                 for (var j = 0; j < sub.length - 1; j++) {
66419                   var a = sub[j];
66420                   var b = sub[j + 1]; // split up the text into small collision boxes
66421
66422                   var num = Math.max(1, Math.floor(geoVecLength(a, b) / boxsize / 2));
66423
66424                   for (var box = 0; box < num; box++) {
66425                     var p = geoVecInterp(a, b, box / num);
66426                     var x0 = p[0] - boxsize - padding;
66427                     var y0 = p[1] - boxsize - padding;
66428                     var x1 = p[0] + boxsize + padding;
66429                     var y1 = p[1] + boxsize + padding;
66430                     bboxes.push({
66431                       minX: Math.min(x0, x1),
66432                       minY: Math.min(y0, y1),
66433                       maxX: Math.max(x0, x1),
66434                       maxY: Math.max(y0, y1)
66435                     });
66436                   }
66437                 }
66438
66439                 if (tryInsert(bboxes, entity.id, false)) {
66440                   // accept this one
66441                   return {
66442                     'font-size': height + 2,
66443                     lineString: lineString(sub),
66444                     startOffset: offset + '%'
66445                   };
66446                 }
66447               }
66448
66449               function reverse(p) {
66450                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
66451                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI / 2 && angle > -Math.PI / 2);
66452               }
66453
66454               function lineString(points) {
66455                 return 'M' + points.join('L');
66456               }
66457
66458               function subpath(points, from, to) {
66459                 var sofar = 0;
66460                 var start, end, i0, i1;
66461
66462                 for (var i = 0; i < points.length - 1; i++) {
66463                   var a = points[i];
66464                   var b = points[i + 1];
66465                   var current = geoVecLength(a, b);
66466                   var portion;
66467
66468                   if (!start && sofar + current >= from) {
66469                     portion = (from - sofar) / current;
66470                     start = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
66471                     i0 = i + 1;
66472                   }
66473
66474                   if (!end && sofar + current >= to) {
66475                     portion = (to - sofar) / current;
66476                     end = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
66477                     i1 = i + 1;
66478                   }
66479
66480                   sofar += current;
66481                 }
66482
66483                 var result = points.slice(i0, i1);
66484                 result.unshift(start);
66485                 result.push(end);
66486                 return result;
66487               }
66488             }
66489
66490             function getAreaLabel(entity, width, height) {
66491               var centroid = path.centroid(entity.asGeoJSON(graph));
66492               var extent = entity.extent(graph);
66493               var areaWidth = projection(extent[1])[0] - projection(extent[0])[0];
66494               if (isNaN(centroid[0]) || areaWidth < 20) return;
66495               var preset = _mainPresetIndex.match(entity, context.graph());
66496               var picon = preset && preset.icon;
66497               var iconSize = 17;
66498               var padding = 2;
66499               var p = {};
66500
66501               if (picon) {
66502                 // icon and label..
66503                 if (addIcon()) {
66504                   addLabel(iconSize + padding);
66505                   return p;
66506                 }
66507               } else {
66508                 // label only..
66509                 if (addLabel(0)) {
66510                   return p;
66511                 }
66512               }
66513
66514               function addIcon() {
66515                 var iconX = centroid[0] - iconSize / 2;
66516                 var iconY = centroid[1] - iconSize / 2;
66517                 var bbox = {
66518                   minX: iconX,
66519                   minY: iconY,
66520                   maxX: iconX + iconSize,
66521                   maxY: iconY + iconSize
66522                 };
66523
66524                 if (tryInsert([bbox], entity.id + 'I', true)) {
66525                   p.transform = 'translate(' + iconX + ',' + iconY + ')';
66526                   return true;
66527                 }
66528
66529                 return false;
66530               }
66531
66532               function addLabel(yOffset) {
66533                 if (width && areaWidth >= width + 20) {
66534                   var labelX = centroid[0];
66535                   var labelY = centroid[1] + yOffset;
66536                   var bbox = {
66537                     minX: labelX - width / 2 - padding,
66538                     minY: labelY - height / 2 - padding,
66539                     maxX: labelX + width / 2 + padding,
66540                     maxY: labelY + height / 2 + padding
66541                   };
66542
66543                   if (tryInsert([bbox], entity.id, true)) {
66544                     p.x = labelX;
66545                     p.y = labelY;
66546                     p.textAnchor = 'middle';
66547                     p.height = height;
66548                     return true;
66549                   }
66550                 }
66551
66552                 return false;
66553               }
66554             } // force insert a singular bounding box
66555             // singular box only, no array, id better be unique
66556
66557
66558             function doInsert(bbox, id) {
66559               bbox.id = id;
66560               var oldbox = _entitybboxes[id];
66561
66562               if (oldbox) {
66563                 _rdrawn.remove(oldbox);
66564               }
66565
66566               _entitybboxes[id] = bbox;
66567
66568               _rdrawn.insert(bbox);
66569             }
66570
66571             function tryInsert(bboxes, id, saveSkipped) {
66572               var skipped = false;
66573
66574               for (var i = 0; i < bboxes.length; i++) {
66575                 var bbox = bboxes[i];
66576                 bbox.id = id; // Check that label is visible
66577
66578                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
66579                   skipped = true;
66580                   break;
66581                 }
66582
66583                 if (_rdrawn.collides(bbox)) {
66584                   skipped = true;
66585                   break;
66586                 }
66587               }
66588
66589               _entitybboxes[id] = bboxes;
66590
66591               if (skipped) {
66592                 if (saveSkipped) {
66593                   _rskipped.load(bboxes);
66594                 }
66595               } else {
66596                 _rdrawn.load(bboxes);
66597               }
66598
66599               return !skipped;
66600             }
66601
66602             var layer = selection.selectAll('.layer-osm.labels');
66603             layer.selectAll('.labels-group').data(['halo', 'label', 'debug']).enter().append('g').attr('class', function (d) {
66604               return 'labels-group ' + d;
66605             });
66606             var halo = layer.selectAll('.labels-group.halo');
66607             var label = layer.selectAll('.labels-group.label');
66608             var debug = layer.selectAll('.labels-group.debug'); // points
66609
66610             drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
66611             drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point); // lines
66612
66613             drawLinePaths(layer, labelled.line, filter, '', positions.line);
66614             drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
66615             drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line); // areas
66616
66617             drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
66618             drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
66619             drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
66620             drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area); // debug
66621
66622             drawCollisionBoxes(debug, _rskipped, 'debug-skipped');
66623             drawCollisionBoxes(debug, _rdrawn, 'debug-drawn');
66624             layer.call(filterLabels);
66625           }
66626
66627           function filterLabels(selection) {
66628             var drawLayer = selection.selectAll('.layer-osm.labels');
66629             var layers = drawLayer.selectAll('.labels-group.halo, .labels-group.label');
66630             layers.selectAll('.nolabel').classed('nolabel', false);
66631             var mouse = context.map().mouse();
66632             var graph = context.graph();
66633             var selectedIDs = context.selectedIDs();
66634             var ids = [];
66635             var pad, bbox; // hide labels near the mouse
66636
66637             if (mouse) {
66638               pad = 20;
66639               bbox = {
66640                 minX: mouse[0] - pad,
66641                 minY: mouse[1] - pad,
66642                 maxX: mouse[0] + pad,
66643                 maxY: mouse[1] + pad
66644               };
66645
66646               var nearMouse = _rdrawn.search(bbox).map(function (entity) {
66647                 return entity.id;
66648               });
66649
66650               ids.push.apply(ids, nearMouse);
66651             } // hide labels on selected nodes (they look weird when dragging / haloed)
66652
66653
66654             for (var i = 0; i < selectedIDs.length; i++) {
66655               var entity = graph.hasEntity(selectedIDs[i]);
66656
66657               if (entity && entity.type === 'node') {
66658                 ids.push(selectedIDs[i]);
66659               }
66660             }
66661
66662             layers.selectAll(utilEntitySelector(ids)).classed('nolabel', true); // draw the mouse bbox if debugging is on..
66663
66664             var debug = selection.selectAll('.labels-group.debug');
66665             var gj = [];
66666
66667             if (context.getDebug('collision')) {
66668               gj = bbox ? [{
66669                 type: 'Polygon',
66670                 coordinates: [[[bbox.minX, bbox.minY], [bbox.maxX, bbox.minY], [bbox.maxX, bbox.maxY], [bbox.minX, bbox.maxY], [bbox.minX, bbox.minY]]]
66671               }] : [];
66672             }
66673
66674             var box = debug.selectAll('.debug-mouse').data(gj); // exit
66675
66676             box.exit().remove(); // enter/update
66677
66678             box.enter().append('path').attr('class', 'debug debug-mouse yellow').merge(box).attr('d', d3_geoPath());
66679           }
66680
66681           var throttleFilterLabels = throttle(filterLabels, 100);
66682
66683           drawLabels.observe = function (selection) {
66684             var listener = function listener() {
66685               throttleFilterLabels(selection);
66686             };
66687
66688             selection.on('mousemove.hidelabels', listener);
66689             context.on('enter.hidelabels', listener);
66690           };
66691
66692           drawLabels.off = function (selection) {
66693             throttleFilterLabels.cancel();
66694             selection.on('mousemove.hidelabels', null);
66695             context.on('enter.hidelabels', null);
66696           };
66697
66698           return drawLabels;
66699         }
66700
66701         var _layerEnabled$1 = false;
66702
66703         var _qaService$1;
66704
66705         function svgImproveOSM(projection, context, dispatch) {
66706           var throttledRedraw = throttle(function () {
66707             return dispatch.call('change');
66708           }, 1000);
66709
66710           var minZoom = 12;
66711           var touchLayer = select(null);
66712           var drawLayer = select(null);
66713           var layerVisible = false;
66714
66715           function markerPath(selection, klass) {
66716             selection.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');
66717           } // Loosely-coupled improveOSM service for fetching issues
66718
66719
66720           function getService() {
66721             if (services.improveOSM && !_qaService$1) {
66722               _qaService$1 = services.improveOSM;
66723
66724               _qaService$1.on('loaded', throttledRedraw);
66725             } else if (!services.improveOSM && _qaService$1) {
66726               _qaService$1 = null;
66727             }
66728
66729             return _qaService$1;
66730           } // Show the markers
66731
66732
66733           function editOn() {
66734             if (!layerVisible) {
66735               layerVisible = true;
66736               drawLayer.style('display', 'block');
66737             }
66738           } // Immediately remove the markers and their touch targets
66739
66740
66741           function editOff() {
66742             if (layerVisible) {
66743               layerVisible = false;
66744               drawLayer.style('display', 'none');
66745               drawLayer.selectAll('.qaItem.improveOSM').remove();
66746               touchLayer.selectAll('.qaItem.improveOSM').remove();
66747             }
66748           } // Enable the layer.  This shows the markers and transitions them to visible.
66749
66750
66751           function layerOn() {
66752             editOn();
66753             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
66754               return dispatch.call('change');
66755             });
66756           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
66757
66758
66759           function layerOff() {
66760             throttledRedraw.cancel();
66761             drawLayer.interrupt();
66762             touchLayer.selectAll('.qaItem.improveOSM').remove();
66763             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
66764               editOff();
66765               dispatch.call('change');
66766             });
66767           } // Update the issue markers
66768
66769
66770           function updateMarkers() {
66771             if (!layerVisible || !_layerEnabled$1) return;
66772             var service = getService();
66773             var selectedID = context.selectedErrorID();
66774             var data = service ? service.getItems(projection) : [];
66775             var getTransform = svgPointTransform(projection); // Draw markers..
66776
66777             var markers = drawLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
66778               return d.id;
66779             }); // exit
66780
66781             markers.exit().remove(); // enter
66782
66783             var markersEnter = markers.enter().append('g').attr('class', function (d) {
66784               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
66785             });
66786             markersEnter.append('polygon').call(markerPath, 'shadow');
66787             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
66788             markersEnter.append('polygon').attr('fill', 'currentColor').call(markerPath, 'qaItem-fill');
66789             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
66790               var picon = d.icon;
66791
66792               if (!picon) {
66793                 return '';
66794               } else {
66795                 var isMaki = /^maki-/.test(picon);
66796                 return "#".concat(picon).concat(isMaki ? '-11' : '');
66797               }
66798             }); // update
66799
66800             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
66801               return d.id === selectedID;
66802             }).attr('transform', getTransform); // Draw targets..
66803
66804             if (touchLayer.empty()) return;
66805             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
66806             var targets = touchLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
66807               return d.id;
66808             }); // exit
66809
66810             targets.exit().remove(); // enter/update
66811
66812             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
66813               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
66814             }).attr('transform', getTransform);
66815
66816             function sortY(a, b) {
66817               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
66818             }
66819           } // Draw the ImproveOSM layer and schedule loading issues and updating markers.
66820
66821
66822           function drawImproveOSM(selection) {
66823             var service = getService();
66824             var surface = context.surface();
66825
66826             if (surface && !surface.empty()) {
66827               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
66828             }
66829
66830             drawLayer = selection.selectAll('.layer-improveOSM').data(service ? [0] : []);
66831             drawLayer.exit().remove();
66832             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-improveOSM').style('display', _layerEnabled$1 ? 'block' : 'none').merge(drawLayer);
66833
66834             if (_layerEnabled$1) {
66835               if (service && ~~context.map().zoom() >= minZoom) {
66836                 editOn();
66837                 service.loadIssues(projection);
66838                 updateMarkers();
66839               } else {
66840                 editOff();
66841               }
66842             }
66843           } // Toggles the layer on and off
66844
66845
66846           drawImproveOSM.enabled = function (val) {
66847             if (!arguments.length) return _layerEnabled$1;
66848             _layerEnabled$1 = val;
66849
66850             if (_layerEnabled$1) {
66851               layerOn();
66852             } else {
66853               layerOff();
66854
66855               if (context.selectedErrorID()) {
66856                 context.enter(modeBrowse(context));
66857               }
66858             }
66859
66860             dispatch.call('change');
66861             return this;
66862           };
66863
66864           drawImproveOSM.supported = function () {
66865             return !!getService();
66866           };
66867
66868           return drawImproveOSM;
66869         }
66870
66871         var _layerEnabled = false;
66872
66873         var _qaService;
66874
66875         function svgOsmose(projection, context, dispatch) {
66876           var throttledRedraw = throttle(function () {
66877             return dispatch.call('change');
66878           }, 1000);
66879
66880           var minZoom = 12;
66881           var touchLayer = select(null);
66882           var drawLayer = select(null);
66883           var layerVisible = false;
66884
66885           function markerPath(selection, klass) {
66886             selection.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');
66887           } // Loosely-coupled osmose service for fetching issues
66888
66889
66890           function getService() {
66891             if (services.osmose && !_qaService) {
66892               _qaService = services.osmose;
66893
66894               _qaService.on('loaded', throttledRedraw);
66895             } else if (!services.osmose && _qaService) {
66896               _qaService = null;
66897             }
66898
66899             return _qaService;
66900           } // Show the markers
66901
66902
66903           function editOn() {
66904             if (!layerVisible) {
66905               layerVisible = true;
66906               drawLayer.style('display', 'block');
66907             }
66908           } // Immediately remove the markers and their touch targets
66909
66910
66911           function editOff() {
66912             if (layerVisible) {
66913               layerVisible = false;
66914               drawLayer.style('display', 'none');
66915               drawLayer.selectAll('.qaItem.osmose').remove();
66916               touchLayer.selectAll('.qaItem.osmose').remove();
66917             }
66918           } // Enable the layer.  This shows the markers and transitions them to visible.
66919
66920
66921           function layerOn() {
66922             editOn();
66923             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
66924               return dispatch.call('change');
66925             });
66926           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
66927
66928
66929           function layerOff() {
66930             throttledRedraw.cancel();
66931             drawLayer.interrupt();
66932             touchLayer.selectAll('.qaItem.osmose').remove();
66933             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
66934               editOff();
66935               dispatch.call('change');
66936             });
66937           } // Update the issue markers
66938
66939
66940           function updateMarkers() {
66941             if (!layerVisible || !_layerEnabled) return;
66942             var service = getService();
66943             var selectedID = context.selectedErrorID();
66944             var data = service ? service.getItems(projection) : [];
66945             var getTransform = svgPointTransform(projection); // Draw markers..
66946
66947             var markers = drawLayer.selectAll('.qaItem.osmose').data(data, function (d) {
66948               return d.id;
66949             }); // exit
66950
66951             markers.exit().remove(); // enter
66952
66953             var markersEnter = markers.enter().append('g').attr('class', function (d) {
66954               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
66955             });
66956             markersEnter.append('polygon').call(markerPath, 'shadow');
66957             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
66958             markersEnter.append('polygon').attr('fill', function (d) {
66959               return service.getColor(d.item);
66960             }).call(markerPath, 'qaItem-fill');
66961             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
66962               var picon = d.icon;
66963
66964               if (!picon) {
66965                 return '';
66966               } else {
66967                 var isMaki = /^maki-/.test(picon);
66968                 return "#".concat(picon).concat(isMaki ? '-11' : '');
66969               }
66970             }); // update
66971
66972             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
66973               return d.id === selectedID;
66974             }).attr('transform', getTransform); // Draw targets..
66975
66976             if (touchLayer.empty()) return;
66977             var fillClass = context.getDebug('target') ? 'pink' : 'nocolor';
66978             var targets = touchLayer.selectAll('.qaItem.osmose').data(data, function (d) {
66979               return d.id;
66980             }); // exit
66981
66982             targets.exit().remove(); // enter/update
66983
66984             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
66985               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
66986             }).attr('transform', getTransform);
66987
66988             function sortY(a, b) {
66989               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
66990             }
66991           } // Draw the Osmose layer and schedule loading issues and updating markers.
66992
66993
66994           function drawOsmose(selection) {
66995             var service = getService();
66996             var surface = context.surface();
66997
66998             if (surface && !surface.empty()) {
66999               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
67000             }
67001
67002             drawLayer = selection.selectAll('.layer-osmose').data(service ? [0] : []);
67003             drawLayer.exit().remove();
67004             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-osmose').style('display', _layerEnabled ? 'block' : 'none').merge(drawLayer);
67005
67006             if (_layerEnabled) {
67007               if (service && ~~context.map().zoom() >= minZoom) {
67008                 editOn();
67009                 service.loadIssues(projection);
67010                 updateMarkers();
67011               } else {
67012                 editOff();
67013               }
67014             }
67015           } // Toggles the layer on and off
67016
67017
67018           drawOsmose.enabled = function (val) {
67019             if (!arguments.length) return _layerEnabled;
67020             _layerEnabled = val;
67021
67022             if (_layerEnabled) {
67023               // Strings supplied by Osmose fetched before showing layer for first time
67024               // NOTE: Currently no way to change locale in iD at runtime, would need to re-call this method if that's ever implemented
67025               // Also, If layer is toggled quickly multiple requests are sent
67026               getService().loadStrings().then(layerOn)["catch"](function (err) {
67027                 console.log(err); // eslint-disable-line no-console
67028               });
67029             } else {
67030               layerOff();
67031
67032               if (context.selectedErrorID()) {
67033                 context.enter(modeBrowse(context));
67034               }
67035             }
67036
67037             dispatch.call('change');
67038             return this;
67039           };
67040
67041           drawOsmose.supported = function () {
67042             return !!getService();
67043           };
67044
67045           return drawOsmose;
67046         }
67047
67048         function svgStreetside(projection, context, dispatch) {
67049           var throttledRedraw = throttle(function () {
67050             dispatch.call('change');
67051           }, 1000);
67052
67053           var minZoom = 14;
67054           var minMarkerZoom = 16;
67055           var minViewfieldZoom = 18;
67056           var layer = select(null);
67057           var _viewerYaw = 0;
67058           var _selectedSequence = null;
67059
67060           var _streetside;
67061           /**
67062            * init().
67063            */
67064
67065
67066           function init() {
67067             if (svgStreetside.initialized) return; // run once
67068
67069             svgStreetside.enabled = false;
67070             svgStreetside.initialized = true;
67071           }
67072           /**
67073            * getService().
67074            */
67075
67076
67077           function getService() {
67078             if (services.streetside && !_streetside) {
67079               _streetside = services.streetside;
67080
67081               _streetside.event.on('viewerChanged.svgStreetside', viewerChanged).on('loadedImages.svgStreetside', throttledRedraw);
67082             } else if (!services.streetside && _streetside) {
67083               _streetside = null;
67084             }
67085
67086             return _streetside;
67087           }
67088           /**
67089            * showLayer().
67090            */
67091
67092
67093           function showLayer() {
67094             var service = getService();
67095             if (!service) return;
67096             editOn();
67097             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
67098               dispatch.call('change');
67099             });
67100           }
67101           /**
67102            * hideLayer().
67103            */
67104
67105
67106           function hideLayer() {
67107             throttledRedraw.cancel();
67108             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
67109           }
67110           /**
67111            * editOn().
67112            */
67113
67114
67115           function editOn() {
67116             layer.style('display', 'block');
67117           }
67118           /**
67119            * editOff().
67120            */
67121
67122
67123           function editOff() {
67124             layer.selectAll('.viewfield-group').remove();
67125             layer.style('display', 'none');
67126           }
67127           /**
67128            * click() Handles 'bubble' point click event.
67129            */
67130
67131
67132           function click(d3_event, d) {
67133             var service = getService();
67134             if (!service) return; // try to preserve the viewer rotation when staying on the same sequence
67135
67136             if (d.sequenceKey !== _selectedSequence) {
67137               _viewerYaw = 0; // reset
67138             }
67139
67140             _selectedSequence = d.sequenceKey;
67141             service.ensureViewerLoaded(context).then(function () {
67142               service.selectImage(context, d.key).yaw(_viewerYaw).showViewer(context);
67143             });
67144             context.map().centerEase(d.loc);
67145           }
67146           /**
67147            * mouseover().
67148            */
67149
67150
67151           function mouseover(d3_event, d) {
67152             var service = getService();
67153             if (service) service.setStyles(context, d);
67154           }
67155           /**
67156            * mouseout().
67157            */
67158
67159
67160           function mouseout() {
67161             var service = getService();
67162             if (service) service.setStyles(context, null);
67163           }
67164           /**
67165            * transform().
67166            */
67167
67168
67169           function transform(d) {
67170             var t = svgPointTransform(projection)(d);
67171             var rot = d.ca + _viewerYaw;
67172
67173             if (rot) {
67174               t += ' rotate(' + Math.floor(rot) + ',0,0)';
67175             }
67176
67177             return t;
67178           }
67179
67180           function viewerChanged() {
67181             var service = getService();
67182             if (!service) return;
67183             var viewer = service.viewer();
67184             if (!viewer) return; // update viewfield rotation
67185
67186             _viewerYaw = viewer.getYaw(); // avoid updating if the map is currently transformed
67187             // e.g. during drags or easing.
67188
67189             if (context.map().isTransformed()) return;
67190             layer.selectAll('.viewfield-group.currentView').attr('transform', transform);
67191           }
67192
67193           function filterBubbles(bubbles) {
67194             var fromDate = context.photos().fromDate();
67195             var toDate = context.photos().toDate();
67196             var usernames = context.photos().usernames();
67197
67198             if (fromDate) {
67199               var fromTimestamp = new Date(fromDate).getTime();
67200               bubbles = bubbles.filter(function (bubble) {
67201                 return new Date(bubble.captured_at).getTime() >= fromTimestamp;
67202               });
67203             }
67204
67205             if (toDate) {
67206               var toTimestamp = new Date(toDate).getTime();
67207               bubbles = bubbles.filter(function (bubble) {
67208                 return new Date(bubble.captured_at).getTime() <= toTimestamp;
67209               });
67210             }
67211
67212             if (usernames) {
67213               bubbles = bubbles.filter(function (bubble) {
67214                 return usernames.indexOf(bubble.captured_by) !== -1;
67215               });
67216             }
67217
67218             return bubbles;
67219           }
67220
67221           function filterSequences(sequences) {
67222             var fromDate = context.photos().fromDate();
67223             var toDate = context.photos().toDate();
67224             var usernames = context.photos().usernames();
67225
67226             if (fromDate) {
67227               var fromTimestamp = new Date(fromDate).getTime();
67228               sequences = sequences.filter(function (sequences) {
67229                 return new Date(sequences.properties.captured_at).getTime() >= fromTimestamp;
67230               });
67231             }
67232
67233             if (toDate) {
67234               var toTimestamp = new Date(toDate).getTime();
67235               sequences = sequences.filter(function (sequences) {
67236                 return new Date(sequences.properties.captured_at).getTime() <= toTimestamp;
67237               });
67238             }
67239
67240             if (usernames) {
67241               sequences = sequences.filter(function (sequences) {
67242                 return usernames.indexOf(sequences.properties.captured_by) !== -1;
67243               });
67244             }
67245
67246             return sequences;
67247           }
67248           /**
67249            * update().
67250            */
67251
67252
67253           function update() {
67254             var viewer = context.container().select('.photoviewer');
67255             var selected = viewer.empty() ? undefined : viewer.datum();
67256             var z = ~~context.map().zoom();
67257             var showMarkers = z >= minMarkerZoom;
67258             var showViewfields = z >= minViewfieldZoom;
67259             var service = getService();
67260             var sequences = [];
67261             var bubbles = [];
67262
67263             if (context.photos().showsPanoramic()) {
67264               sequences = service ? service.sequences(projection) : [];
67265               bubbles = service && showMarkers ? service.bubbles(projection) : [];
67266               sequences = filterSequences(sequences);
67267               bubbles = filterBubbles(bubbles);
67268             }
67269
67270             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
67271               return d.properties.key;
67272             }); // exit
67273
67274             traces.exit().remove(); // enter/update
67275
67276             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
67277             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(bubbles, function (d) {
67278               // force reenter once bubbles are attached to a sequence
67279               return d.key + (d.sequenceKey ? 'v1' : 'v0');
67280             }); // exit
67281
67282             groups.exit().remove(); // enter
67283
67284             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
67285             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
67286
67287             var markers = groups.merge(groupsEnter).sort(function (a, b) {
67288               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1];
67289             }).attr('transform', transform).select('.viewfield-scale');
67290             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
67291             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
67292             viewfields.exit().remove(); // viewfields may or may not be drawn...
67293             // but if they are, draw below the circles
67294
67295             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
67296
67297             function viewfieldPath() {
67298               var d = this.parentNode.__data__;
67299
67300               if (d.pano) {
67301                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
67302               } else {
67303                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
67304               }
67305             }
67306           }
67307           /**
67308            * drawImages()
67309            * drawImages is the method that is returned (and that runs) every time 'svgStreetside()' is called.
67310            * 'svgStreetside()' is called from index.js
67311            */
67312
67313
67314           function drawImages(selection) {
67315             var enabled = svgStreetside.enabled;
67316             var service = getService();
67317             layer = selection.selectAll('.layer-streetside-images').data(service ? [0] : []);
67318             layer.exit().remove();
67319             var layerEnter = layer.enter().append('g').attr('class', 'layer-streetside-images').style('display', enabled ? 'block' : 'none');
67320             layerEnter.append('g').attr('class', 'sequences');
67321             layerEnter.append('g').attr('class', 'markers');
67322             layer = layerEnter.merge(layer);
67323
67324             if (enabled) {
67325               if (service && ~~context.map().zoom() >= minZoom) {
67326                 editOn();
67327                 update();
67328                 service.loadBubbles(projection);
67329               } else {
67330                 editOff();
67331               }
67332             }
67333           }
67334           /**
67335            * drawImages.enabled().
67336            */
67337
67338
67339           drawImages.enabled = function (_) {
67340             if (!arguments.length) return svgStreetside.enabled;
67341             svgStreetside.enabled = _;
67342
67343             if (svgStreetside.enabled) {
67344               showLayer();
67345               context.photos().on('change.streetside', update);
67346             } else {
67347               hideLayer();
67348               context.photos().on('change.streetside', null);
67349             }
67350
67351             dispatch.call('change');
67352             return this;
67353           };
67354           /**
67355            * drawImages.supported().
67356            */
67357
67358
67359           drawImages.supported = function () {
67360             return !!getService();
67361           };
67362
67363           init();
67364           return drawImages;
67365         }
67366
67367         function svgMapillaryImages(projection, context, dispatch) {
67368           var throttledRedraw = throttle(function () {
67369             dispatch.call('change');
67370           }, 1000);
67371
67372           var minZoom = 12;
67373           var minMarkerZoom = 16;
67374           var minViewfieldZoom = 18;
67375           var layer = select(null);
67376
67377           var _mapillary;
67378
67379           function init() {
67380             if (svgMapillaryImages.initialized) return; // run once
67381
67382             svgMapillaryImages.enabled = false;
67383             svgMapillaryImages.initialized = true;
67384           }
67385
67386           function getService() {
67387             if (services.mapillary && !_mapillary) {
67388               _mapillary = services.mapillary;
67389
67390               _mapillary.event.on('loadedImages', throttledRedraw);
67391             } else if (!services.mapillary && _mapillary) {
67392               _mapillary = null;
67393             }
67394
67395             return _mapillary;
67396           }
67397
67398           function showLayer() {
67399             var service = getService();
67400             if (!service) return;
67401             editOn();
67402             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
67403               dispatch.call('change');
67404             });
67405           }
67406
67407           function hideLayer() {
67408             throttledRedraw.cancel();
67409             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
67410           }
67411
67412           function editOn() {
67413             layer.style('display', 'block');
67414           }
67415
67416           function editOff() {
67417             layer.selectAll('.viewfield-group').remove();
67418             layer.style('display', 'none');
67419           }
67420
67421           function click(d3_event, image) {
67422             var service = getService();
67423             if (!service) return;
67424             service.ensureViewerLoaded(context).then(function () {
67425               service.selectImage(context, image.id).showViewer(context);
67426             });
67427             context.map().centerEase(image.loc);
67428           }
67429
67430           function mouseover(d3_event, image) {
67431             var service = getService();
67432             if (service) service.setStyles(context, image);
67433           }
67434
67435           function mouseout() {
67436             var service = getService();
67437             if (service) service.setStyles(context, null);
67438           }
67439
67440           function transform(d) {
67441             var t = svgPointTransform(projection)(d);
67442
67443             if (d.ca) {
67444               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
67445             }
67446
67447             return t;
67448           }
67449
67450           function filterImages(images) {
67451             var showsPano = context.photos().showsPanoramic();
67452             var showsFlat = context.photos().showsFlat();
67453             var fromDate = context.photos().fromDate();
67454             var toDate = context.photos().toDate();
67455
67456             if (!showsPano || !showsFlat) {
67457               images = images.filter(function (image) {
67458                 if (image.is_pano) return showsPano;
67459                 return showsFlat;
67460               });
67461             }
67462
67463             if (fromDate) {
67464               images = images.filter(function (image) {
67465                 return new Date(image.captured_at).getTime() >= new Date(fromDate).getTime();
67466               });
67467             }
67468
67469             if (toDate) {
67470               images = images.filter(function (image) {
67471                 return new Date(image.captured_at).getTime() <= new Date(toDate).getTime();
67472               });
67473             }
67474
67475             return images;
67476           }
67477
67478           function filterSequences(sequences) {
67479             var showsPano = context.photos().showsPanoramic();
67480             var showsFlat = context.photos().showsFlat();
67481             var fromDate = context.photos().fromDate();
67482             var toDate = context.photos().toDate();
67483
67484             if (!showsPano || !showsFlat) {
67485               sequences = sequences.filter(function (sequence) {
67486                 if (sequence.properties.hasOwnProperty('is_pano')) {
67487                   if (sequence.properties.is_pano) return showsPano;
67488                   return showsFlat;
67489                 }
67490
67491                 return false;
67492               });
67493             }
67494
67495             if (fromDate) {
67496               sequences = sequences.filter(function (sequence) {
67497                 return new Date(sequence.properties.captured_at).getTime() >= new Date(fromDate).getTime().toString();
67498               });
67499             }
67500
67501             if (toDate) {
67502               sequences = sequences.filter(function (sequence) {
67503                 return new Date(sequence.properties.captured_at).getTime() <= new Date(toDate).getTime().toString();
67504               });
67505             }
67506
67507             return sequences;
67508           }
67509
67510           function update() {
67511             var z = ~~context.map().zoom();
67512             var showMarkers = z >= minMarkerZoom;
67513             var showViewfields = z >= minViewfieldZoom;
67514             var service = getService();
67515             var sequences = service ? service.sequences(projection) : [];
67516             var images = service && showMarkers ? service.images(projection) : [];
67517             images = filterImages(images);
67518             sequences = filterSequences(sequences);
67519             service.filterViewer(context);
67520             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
67521               return d.properties.id;
67522             }); // exit
67523
67524             traces.exit().remove(); // enter/update
67525
67526             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
67527             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
67528               return d.id;
67529             }); // exit
67530
67531             groups.exit().remove(); // enter
67532
67533             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
67534             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
67535
67536             var markers = groups.merge(groupsEnter).sort(function (a, b) {
67537               return b.loc[1] - a.loc[1]; // sort Y
67538             }).attr('transform', transform).select('.viewfield-scale');
67539             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
67540             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
67541             viewfields.exit().remove();
67542             viewfields.enter() // viewfields may or may not be drawn...
67543             .insert('path', 'circle') // but if they are, draw below the circles
67544             .attr('class', 'viewfield').classed('pano', function () {
67545               return this.parentNode.__data__.is_pano;
67546             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
67547
67548             function viewfieldPath() {
67549               if (this.parentNode.__data__.is_pano) {
67550                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
67551               } else {
67552                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
67553               }
67554             }
67555           }
67556
67557           function drawImages(selection) {
67558             var enabled = svgMapillaryImages.enabled;
67559             var service = getService();
67560             layer = selection.selectAll('.layer-mapillary').data(service ? [0] : []);
67561             layer.exit().remove();
67562             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary').style('display', enabled ? 'block' : 'none');
67563             layerEnter.append('g').attr('class', 'sequences');
67564             layerEnter.append('g').attr('class', 'markers');
67565             layer = layerEnter.merge(layer);
67566
67567             if (enabled) {
67568               if (service && ~~context.map().zoom() >= minZoom) {
67569                 editOn();
67570                 update();
67571                 service.loadImages(projection);
67572               } else {
67573                 editOff();
67574               }
67575             }
67576           }
67577
67578           drawImages.enabled = function (_) {
67579             if (!arguments.length) return svgMapillaryImages.enabled;
67580             svgMapillaryImages.enabled = _;
67581
67582             if (svgMapillaryImages.enabled) {
67583               showLayer();
67584               context.photos().on('change.mapillary_images', update);
67585             } else {
67586               hideLayer();
67587               context.photos().on('change.mapillary_images', null);
67588             }
67589
67590             dispatch.call('change');
67591             return this;
67592           };
67593
67594           drawImages.supported = function () {
67595             return !!getService();
67596           };
67597
67598           init();
67599           return drawImages;
67600         }
67601
67602         function svgMapillaryPosition(projection, context) {
67603           var throttledRedraw = throttle(function () {
67604             update();
67605           }, 1000);
67606
67607           var minZoom = 12;
67608           var minViewfieldZoom = 18;
67609           var layer = select(null);
67610
67611           var _mapillary;
67612
67613           var viewerCompassAngle;
67614
67615           function init() {
67616             if (svgMapillaryPosition.initialized) return; // run once
67617
67618             svgMapillaryPosition.initialized = true;
67619           }
67620
67621           function getService() {
67622             if (services.mapillary && !_mapillary) {
67623               _mapillary = services.mapillary;
67624
67625               _mapillary.event.on('imageChanged', throttledRedraw);
67626
67627               _mapillary.event.on('bearingChanged', function (e) {
67628                 viewerCompassAngle = e.bearing;
67629                 if (context.map().isTransformed()) return;
67630                 layer.selectAll('.viewfield-group.currentView').filter(function (d) {
67631                   return d.is_pano;
67632                 }).attr('transform', transform);
67633               });
67634             } else if (!services.mapillary && _mapillary) {
67635               _mapillary = null;
67636             }
67637
67638             return _mapillary;
67639           }
67640
67641           function editOn() {
67642             layer.style('display', 'block');
67643           }
67644
67645           function editOff() {
67646             layer.selectAll('.viewfield-group').remove();
67647             layer.style('display', 'none');
67648           }
67649
67650           function transform(d) {
67651             var t = svgPointTransform(projection)(d);
67652
67653             if (d.is_pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
67654               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
67655             } else if (d.ca) {
67656               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
67657             }
67658
67659             return t;
67660           }
67661
67662           function update() {
67663             var z = ~~context.map().zoom();
67664             var showViewfields = z >= minViewfieldZoom;
67665             var service = getService();
67666             var image = service && service.getActiveImage();
67667             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(image ? [image] : [], function (d) {
67668               return d.id;
67669             }); // exit
67670
67671             groups.exit().remove(); // enter
67672
67673             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group currentView highlighted');
67674             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
67675
67676             var markers = groups.merge(groupsEnter).attr('transform', transform).select('.viewfield-scale');
67677             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
67678             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
67679             viewfields.exit().remove();
67680             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');
67681           }
67682
67683           function drawImages(selection) {
67684             var service = getService();
67685             layer = selection.selectAll('.layer-mapillary-position').data(service ? [0] : []);
67686             layer.exit().remove();
67687             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary-position');
67688             layerEnter.append('g').attr('class', 'markers');
67689             layer = layerEnter.merge(layer);
67690
67691             if (service && ~~context.map().zoom() >= minZoom) {
67692               editOn();
67693               update();
67694             } else {
67695               editOff();
67696             }
67697           }
67698
67699           drawImages.enabled = function () {
67700             update();
67701             return this;
67702           };
67703
67704           drawImages.supported = function () {
67705             return !!getService();
67706           };
67707
67708           init();
67709           return drawImages;
67710         }
67711
67712         function svgMapillarySigns(projection, context, dispatch) {
67713           var throttledRedraw = throttle(function () {
67714             dispatch.call('change');
67715           }, 1000);
67716
67717           var minZoom = 12;
67718           var layer = select(null);
67719
67720           var _mapillary;
67721
67722           function init() {
67723             if (svgMapillarySigns.initialized) return; // run once
67724
67725             svgMapillarySigns.enabled = false;
67726             svgMapillarySigns.initialized = true;
67727           }
67728
67729           function getService() {
67730             if (services.mapillary && !_mapillary) {
67731               _mapillary = services.mapillary;
67732
67733               _mapillary.event.on('loadedSigns', throttledRedraw);
67734             } else if (!services.mapillary && _mapillary) {
67735               _mapillary = null;
67736             }
67737
67738             return _mapillary;
67739           }
67740
67741           function showLayer() {
67742             var service = getService();
67743             if (!service) return;
67744             service.loadSignResources(context);
67745             editOn();
67746           }
67747
67748           function hideLayer() {
67749             throttledRedraw.cancel();
67750             editOff();
67751           }
67752
67753           function editOn() {
67754             layer.style('display', 'block');
67755           }
67756
67757           function editOff() {
67758             layer.selectAll('.icon-sign').remove();
67759             layer.style('display', 'none');
67760           }
67761
67762           function click(d3_event, d) {
67763             var service = getService();
67764             if (!service) return;
67765             context.map().centerEase(d.loc);
67766             var selectedImageId = service.getActiveImage() && service.getActiveImage().id;
67767             service.getDetections(d.id).then(function (detections) {
67768               if (detections.length) {
67769                 var imageId = detections[0].image.id;
67770
67771                 if (imageId === selectedImageId) {
67772                   service.highlightDetection(detections[0]).selectImage(context, imageId);
67773                 } else {
67774                   service.ensureViewerLoaded(context).then(function () {
67775                     service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
67776                   });
67777                 }
67778               }
67779             });
67780           }
67781
67782           function filterData(detectedFeatures) {
67783             var fromDate = context.photos().fromDate();
67784             var toDate = context.photos().toDate();
67785
67786             if (fromDate) {
67787               var fromTimestamp = new Date(fromDate).getTime();
67788               detectedFeatures = detectedFeatures.filter(function (feature) {
67789                 return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
67790               });
67791             }
67792
67793             if (toDate) {
67794               var toTimestamp = new Date(toDate).getTime();
67795               detectedFeatures = detectedFeatures.filter(function (feature) {
67796                 return new Date(feature.first_seen_at).getTime() <= toTimestamp;
67797               });
67798             }
67799
67800             return detectedFeatures;
67801           }
67802
67803           function update() {
67804             var service = getService();
67805             var data = service ? service.signs(projection) : [];
67806             data = filterData(data);
67807             var transform = svgPointTransform(projection);
67808             var signs = layer.selectAll('.icon-sign').data(data, function (d) {
67809               return d.id;
67810             }); // exit
67811
67812             signs.exit().remove(); // enter
67813
67814             var enter = signs.enter().append('g').attr('class', 'icon-sign icon-detected').on('click', click);
67815             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
67816               return '#' + d.value;
67817             });
67818             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
67819
67820             signs.merge(enter).attr('transform', transform);
67821           }
67822
67823           function drawSigns(selection) {
67824             var enabled = svgMapillarySigns.enabled;
67825             var service = getService();
67826             layer = selection.selectAll('.layer-mapillary-signs').data(service ? [0] : []);
67827             layer.exit().remove();
67828             layer = layer.enter().append('g').attr('class', 'layer-mapillary-signs layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
67829
67830             if (enabled) {
67831               if (service && ~~context.map().zoom() >= minZoom) {
67832                 editOn();
67833                 update();
67834                 service.loadSigns(projection);
67835                 service.showSignDetections(true);
67836               } else {
67837                 editOff();
67838               }
67839             } else if (service) {
67840               service.showSignDetections(false);
67841             }
67842           }
67843
67844           drawSigns.enabled = function (_) {
67845             if (!arguments.length) return svgMapillarySigns.enabled;
67846             svgMapillarySigns.enabled = _;
67847
67848             if (svgMapillarySigns.enabled) {
67849               showLayer();
67850               context.photos().on('change.mapillary_signs', update);
67851             } else {
67852               hideLayer();
67853               context.photos().on('change.mapillary_signs', null);
67854             }
67855
67856             dispatch.call('change');
67857             return this;
67858           };
67859
67860           drawSigns.supported = function () {
67861             return !!getService();
67862           };
67863
67864           init();
67865           return drawSigns;
67866         }
67867
67868         function svgMapillaryMapFeatures(projection, context, dispatch) {
67869           var throttledRedraw = throttle(function () {
67870             dispatch.call('change');
67871           }, 1000);
67872
67873           var minZoom = 12;
67874           var layer = select(null);
67875
67876           var _mapillary;
67877
67878           function init() {
67879             if (svgMapillaryMapFeatures.initialized) return; // run once
67880
67881             svgMapillaryMapFeatures.enabled = false;
67882             svgMapillaryMapFeatures.initialized = true;
67883           }
67884
67885           function getService() {
67886             if (services.mapillary && !_mapillary) {
67887               _mapillary = services.mapillary;
67888
67889               _mapillary.event.on('loadedMapFeatures', throttledRedraw);
67890             } else if (!services.mapillary && _mapillary) {
67891               _mapillary = null;
67892             }
67893
67894             return _mapillary;
67895           }
67896
67897           function showLayer() {
67898             var service = getService();
67899             if (!service) return;
67900             service.loadObjectResources(context);
67901             editOn();
67902           }
67903
67904           function hideLayer() {
67905             throttledRedraw.cancel();
67906             editOff();
67907           }
67908
67909           function editOn() {
67910             layer.style('display', 'block');
67911           }
67912
67913           function editOff() {
67914             layer.selectAll('.icon-map-feature').remove();
67915             layer.style('display', 'none');
67916           }
67917
67918           function click(d3_event, d) {
67919             var service = getService();
67920             if (!service) return;
67921             context.map().centerEase(d.loc);
67922             var selectedImageId = service.getActiveImage() && service.getActiveImage().id;
67923             service.getDetections(d.id).then(function (detections) {
67924               if (detections.length) {
67925                 var imageId = detections[0].image.id;
67926
67927                 if (imageId === selectedImageId) {
67928                   service.highlightDetection(detections[0]).selectImage(context, imageId);
67929                 } else {
67930                   service.ensureViewerLoaded(context).then(function () {
67931                     service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
67932                   });
67933                 }
67934               }
67935             });
67936           }
67937
67938           function filterData(detectedFeatures) {
67939             var fromDate = context.photos().fromDate();
67940             var toDate = context.photos().toDate();
67941
67942             if (fromDate) {
67943               detectedFeatures = detectedFeatures.filter(function (feature) {
67944                 return new Date(feature.last_seen_at).getTime() >= new Date(fromDate).getTime();
67945               });
67946             }
67947
67948             if (toDate) {
67949               detectedFeatures = detectedFeatures.filter(function (feature) {
67950                 return new Date(feature.first_seen_at).getTime() <= new Date(toDate).getTime();
67951               });
67952             }
67953
67954             return detectedFeatures;
67955           }
67956
67957           function update() {
67958             var service = getService();
67959             var data = service ? service.mapFeatures(projection) : [];
67960             data = filterData(data);
67961             var transform = svgPointTransform(projection);
67962             var mapFeatures = layer.selectAll('.icon-map-feature').data(data, function (d) {
67963               return d.id;
67964             }); // exit
67965
67966             mapFeatures.exit().remove(); // enter
67967
67968             var enter = mapFeatures.enter().append('g').attr('class', 'icon-map-feature icon-detected').on('click', click);
67969             enter.append('title').text(function (d) {
67970               var id = d.value.replace(/--/g, '.').replace(/-/g, '_');
67971               return _t('mapillary_map_features.' + id);
67972             });
67973             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
67974               if (d.value === 'object--billboard') {
67975                 // no billboard icon right now, so use the advertisement icon
67976                 return '#object--sign--advertisement';
67977               }
67978
67979               return '#' + d.value;
67980             });
67981             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
67982
67983             mapFeatures.merge(enter).attr('transform', transform);
67984           }
67985
67986           function drawMapFeatures(selection) {
67987             var enabled = svgMapillaryMapFeatures.enabled;
67988             var service = getService();
67989             layer = selection.selectAll('.layer-mapillary-map-features').data(service ? [0] : []);
67990             layer.exit().remove();
67991             layer = layer.enter().append('g').attr('class', 'layer-mapillary-map-features layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
67992
67993             if (enabled) {
67994               if (service && ~~context.map().zoom() >= minZoom) {
67995                 editOn();
67996                 update();
67997                 service.loadMapFeatures(projection);
67998                 service.showFeatureDetections(true);
67999               } else {
68000                 editOff();
68001               }
68002             } else if (service) {
68003               service.showFeatureDetections(false);
68004             }
68005           }
68006
68007           drawMapFeatures.enabled = function (_) {
68008             if (!arguments.length) return svgMapillaryMapFeatures.enabled;
68009             svgMapillaryMapFeatures.enabled = _;
68010
68011             if (svgMapillaryMapFeatures.enabled) {
68012               showLayer();
68013               context.photos().on('change.mapillary_map_features', update);
68014             } else {
68015               hideLayer();
68016               context.photos().on('change.mapillary_map_features', null);
68017             }
68018
68019             dispatch.call('change');
68020             return this;
68021           };
68022
68023           drawMapFeatures.supported = function () {
68024             return !!getService();
68025           };
68026
68027           init();
68028           return drawMapFeatures;
68029         }
68030
68031         function svgOpenstreetcamImages(projection, context, dispatch) {
68032           var throttledRedraw = throttle(function () {
68033             dispatch.call('change');
68034           }, 1000);
68035
68036           var minZoom = 12;
68037           var minMarkerZoom = 16;
68038           var minViewfieldZoom = 18;
68039           var layer = select(null);
68040
68041           var _openstreetcam;
68042
68043           function init() {
68044             if (svgOpenstreetcamImages.initialized) return; // run once
68045
68046             svgOpenstreetcamImages.enabled = false;
68047             svgOpenstreetcamImages.initialized = true;
68048           }
68049
68050           function getService() {
68051             if (services.openstreetcam && !_openstreetcam) {
68052               _openstreetcam = services.openstreetcam;
68053
68054               _openstreetcam.event.on('loadedImages', throttledRedraw);
68055             } else if (!services.openstreetcam && _openstreetcam) {
68056               _openstreetcam = null;
68057             }
68058
68059             return _openstreetcam;
68060           }
68061
68062           function showLayer() {
68063             var service = getService();
68064             if (!service) return;
68065             editOn();
68066             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
68067               dispatch.call('change');
68068             });
68069           }
68070
68071           function hideLayer() {
68072             throttledRedraw.cancel();
68073             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
68074           }
68075
68076           function editOn() {
68077             layer.style('display', 'block');
68078           }
68079
68080           function editOff() {
68081             layer.selectAll('.viewfield-group').remove();
68082             layer.style('display', 'none');
68083           }
68084
68085           function click(d3_event, d) {
68086             var service = getService();
68087             if (!service) return;
68088             service.ensureViewerLoaded(context).then(function () {
68089               service.selectImage(context, d.key).showViewer(context);
68090             });
68091             context.map().centerEase(d.loc);
68092           }
68093
68094           function mouseover(d3_event, d) {
68095             var service = getService();
68096             if (service) service.setStyles(context, d);
68097           }
68098
68099           function mouseout() {
68100             var service = getService();
68101             if (service) service.setStyles(context, null);
68102           }
68103
68104           function transform(d) {
68105             var t = svgPointTransform(projection)(d);
68106
68107             if (d.ca) {
68108               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
68109             }
68110
68111             return t;
68112           }
68113
68114           function filterImages(images) {
68115             var fromDate = context.photos().fromDate();
68116             var toDate = context.photos().toDate();
68117             var usernames = context.photos().usernames();
68118
68119             if (fromDate) {
68120               var fromTimestamp = new Date(fromDate).getTime();
68121               images = images.filter(function (item) {
68122                 return new Date(item.captured_at).getTime() >= fromTimestamp;
68123               });
68124             }
68125
68126             if (toDate) {
68127               var toTimestamp = new Date(toDate).getTime();
68128               images = images.filter(function (item) {
68129                 return new Date(item.captured_at).getTime() <= toTimestamp;
68130               });
68131             }
68132
68133             if (usernames) {
68134               images = images.filter(function (item) {
68135                 return usernames.indexOf(item.captured_by) !== -1;
68136               });
68137             }
68138
68139             return images;
68140           }
68141
68142           function filterSequences(sequences) {
68143             var fromDate = context.photos().fromDate();
68144             var toDate = context.photos().toDate();
68145             var usernames = context.photos().usernames();
68146
68147             if (fromDate) {
68148               var fromTimestamp = new Date(fromDate).getTime();
68149               sequences = sequences.filter(function (image) {
68150                 return new Date(image.properties.captured_at).getTime() >= fromTimestamp;
68151               });
68152             }
68153
68154             if (toDate) {
68155               var toTimestamp = new Date(toDate).getTime();
68156               sequences = sequences.filter(function (image) {
68157                 return new Date(image.properties.captured_at).getTime() <= toTimestamp;
68158               });
68159             }
68160
68161             if (usernames) {
68162               sequences = sequences.filter(function (image) {
68163                 return usernames.indexOf(image.properties.captured_by) !== -1;
68164               });
68165             }
68166
68167             return sequences;
68168           }
68169
68170           function update() {
68171             var viewer = context.container().select('.photoviewer');
68172             var selected = viewer.empty() ? undefined : viewer.datum();
68173             var z = ~~context.map().zoom();
68174             var showMarkers = z >= minMarkerZoom;
68175             var showViewfields = z >= minViewfieldZoom;
68176             var service = getService();
68177             var sequences = [];
68178             var images = [];
68179
68180             if (context.photos().showsFlat()) {
68181               sequences = service ? service.sequences(projection) : [];
68182               images = service && showMarkers ? service.images(projection) : [];
68183               sequences = filterSequences(sequences);
68184               images = filterImages(images);
68185             }
68186
68187             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
68188               return d.properties.key;
68189             }); // exit
68190
68191             traces.exit().remove(); // enter/update
68192
68193             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
68194             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
68195               return d.key;
68196             }); // exit
68197
68198             groups.exit().remove(); // enter
68199
68200             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
68201             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
68202
68203             var markers = groups.merge(groupsEnter).sort(function (a, b) {
68204               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1]; // sort Y
68205             }).attr('transform', transform).select('.viewfield-scale');
68206             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
68207             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
68208             viewfields.exit().remove();
68209             viewfields.enter() // viewfields may or may not be drawn...
68210             .insert('path', 'circle') // but if they are, draw below the circles
68211             .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');
68212           }
68213
68214           function drawImages(selection) {
68215             var enabled = svgOpenstreetcamImages.enabled,
68216                 service = getService();
68217             layer = selection.selectAll('.layer-openstreetcam').data(service ? [0] : []);
68218             layer.exit().remove();
68219             var layerEnter = layer.enter().append('g').attr('class', 'layer-openstreetcam').style('display', enabled ? 'block' : 'none');
68220             layerEnter.append('g').attr('class', 'sequences');
68221             layerEnter.append('g').attr('class', 'markers');
68222             layer = layerEnter.merge(layer);
68223
68224             if (enabled) {
68225               if (service && ~~context.map().zoom() >= minZoom) {
68226                 editOn();
68227                 update();
68228                 service.loadImages(projection);
68229               } else {
68230                 editOff();
68231               }
68232             }
68233           }
68234
68235           drawImages.enabled = function (_) {
68236             if (!arguments.length) return svgOpenstreetcamImages.enabled;
68237             svgOpenstreetcamImages.enabled = _;
68238
68239             if (svgOpenstreetcamImages.enabled) {
68240               showLayer();
68241               context.photos().on('change.openstreetcam_images', update);
68242             } else {
68243               hideLayer();
68244               context.photos().on('change.openstreetcam_images', null);
68245             }
68246
68247             dispatch.call('change');
68248             return this;
68249           };
68250
68251           drawImages.supported = function () {
68252             return !!getService();
68253           };
68254
68255           init();
68256           return drawImages;
68257         }
68258
68259         function svgOsm(projection, context, dispatch) {
68260           var enabled = true;
68261
68262           function drawOsm(selection) {
68263             selection.selectAll('.layer-osm').data(['covered', 'areas', 'lines', 'points', 'labels']).enter().append('g').attr('class', function (d) {
68264               return 'layer-osm ' + d;
68265             });
68266             selection.selectAll('.layer-osm.points').selectAll('.points-group').data(['points', 'midpoints', 'vertices', 'turns']).enter().append('g').attr('class', function (d) {
68267               return 'points-group ' + d;
68268             });
68269           }
68270
68271           function showLayer() {
68272             var layer = context.surface().selectAll('.data-layer.osm');
68273             layer.interrupt();
68274             layer.classed('disabled', false).style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
68275               dispatch.call('change');
68276             });
68277           }
68278
68279           function hideLayer() {
68280             var layer = context.surface().selectAll('.data-layer.osm');
68281             layer.interrupt();
68282             layer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
68283               layer.classed('disabled', true);
68284               dispatch.call('change');
68285             });
68286           }
68287
68288           drawOsm.enabled = function (val) {
68289             if (!arguments.length) return enabled;
68290             enabled = val;
68291
68292             if (enabled) {
68293               showLayer();
68294             } else {
68295               hideLayer();
68296             }
68297
68298             dispatch.call('change');
68299             return this;
68300           };
68301
68302           return drawOsm;
68303         }
68304
68305         var _notesEnabled = false;
68306
68307         var _osmService;
68308
68309         function svgNotes(projection, context, dispatch) {
68310           if (!dispatch) {
68311             dispatch = dispatch$8('change');
68312           }
68313
68314           var throttledRedraw = throttle(function () {
68315             dispatch.call('change');
68316           }, 1000);
68317
68318           var minZoom = 12;
68319           var touchLayer = select(null);
68320           var drawLayer = select(null);
68321           var _notesVisible = false;
68322
68323           function markerPath(selection, klass) {
68324             selection.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');
68325           } // Loosely-coupled osm service for fetching notes.
68326
68327
68328           function getService() {
68329             if (services.osm && !_osmService) {
68330               _osmService = services.osm;
68331
68332               _osmService.on('loadedNotes', throttledRedraw);
68333             } else if (!services.osm && _osmService) {
68334               _osmService = null;
68335             }
68336
68337             return _osmService;
68338           } // Show the notes
68339
68340
68341           function editOn() {
68342             if (!_notesVisible) {
68343               _notesVisible = true;
68344               drawLayer.style('display', 'block');
68345             }
68346           } // Immediately remove the notes and their touch targets
68347
68348
68349           function editOff() {
68350             if (_notesVisible) {
68351               _notesVisible = false;
68352               drawLayer.style('display', 'none');
68353               drawLayer.selectAll('.note').remove();
68354               touchLayer.selectAll('.note').remove();
68355             }
68356           } // Enable the layer.  This shows the notes and transitions them to visible.
68357
68358
68359           function layerOn() {
68360             editOn();
68361             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
68362               dispatch.call('change');
68363             });
68364           } // Disable the layer.  This transitions the layer invisible and then hides the notes.
68365
68366
68367           function layerOff() {
68368             throttledRedraw.cancel();
68369             drawLayer.interrupt();
68370             touchLayer.selectAll('.note').remove();
68371             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
68372               editOff();
68373               dispatch.call('change');
68374             });
68375           } // Update the note markers
68376
68377
68378           function updateMarkers() {
68379             if (!_notesVisible || !_notesEnabled) return;
68380             var service = getService();
68381             var selectedID = context.selectedNoteID();
68382             var data = service ? service.notes(projection) : [];
68383             var getTransform = svgPointTransform(projection); // Draw markers..
68384
68385             var notes = drawLayer.selectAll('.note').data(data, function (d) {
68386               return d.status + d.id;
68387             }); // exit
68388
68389             notes.exit().remove(); // enter
68390
68391             var notesEnter = notes.enter().append('g').attr('class', function (d) {
68392               return 'note note-' + d.id + ' ' + d.status;
68393             }).classed('new', function (d) {
68394               return d.id < 0;
68395             });
68396             notesEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
68397             notesEnter.append('path').call(markerPath, 'shadow');
68398             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');
68399             notesEnter.selectAll('.icon-annotation').data(function (d) {
68400               return [d];
68401             }).enter().append('use').attr('class', 'icon-annotation').attr('width', '10px').attr('height', '10px').attr('x', '-3px').attr('y', '-19px').attr('xlink:href', function (d) {
68402               if (d.id < 0) return '#iD-icon-plus';
68403               if (d.status === 'open') return '#iD-icon-close';
68404               return '#iD-icon-apply';
68405             }); // update
68406
68407             notes.merge(notesEnter).sort(sortY).classed('selected', function (d) {
68408               var mode = context.mode();
68409               var isMoving = mode && mode.id === 'drag-note'; // no shadows when dragging
68410
68411               return !isMoving && d.id === selectedID;
68412             }).attr('transform', getTransform); // Draw targets..
68413
68414             if (touchLayer.empty()) return;
68415             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
68416             var targets = touchLayer.selectAll('.note').data(data, function (d) {
68417               return d.id;
68418             }); // exit
68419
68420             targets.exit().remove(); // enter/update
68421
68422             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
68423               var newClass = d.id < 0 ? 'new' : '';
68424               return 'note target note-' + d.id + ' ' + fillClass + newClass;
68425             }).attr('transform', getTransform);
68426
68427             function sortY(a, b) {
68428               if (a.id === selectedID) return 1;
68429               if (b.id === selectedID) return -1;
68430               return b.loc[1] - a.loc[1];
68431             }
68432           } // Draw the notes layer and schedule loading notes and updating markers.
68433
68434
68435           function drawNotes(selection) {
68436             var service = getService();
68437             var surface = context.surface();
68438
68439             if (surface && !surface.empty()) {
68440               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
68441             }
68442
68443             drawLayer = selection.selectAll('.layer-notes').data(service ? [0] : []);
68444             drawLayer.exit().remove();
68445             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-notes').style('display', _notesEnabled ? 'block' : 'none').merge(drawLayer);
68446
68447             if (_notesEnabled) {
68448               if (service && ~~context.map().zoom() >= minZoom) {
68449                 editOn();
68450                 service.loadNotes(projection);
68451                 updateMarkers();
68452               } else {
68453                 editOff();
68454               }
68455             }
68456           } // Toggles the layer on and off
68457
68458
68459           drawNotes.enabled = function (val) {
68460             if (!arguments.length) return _notesEnabled;
68461             _notesEnabled = val;
68462
68463             if (_notesEnabled) {
68464               layerOn();
68465             } else {
68466               layerOff();
68467
68468               if (context.selectedNoteID()) {
68469                 context.enter(modeBrowse(context));
68470               }
68471             }
68472
68473             dispatch.call('change');
68474             return this;
68475           };
68476
68477           return drawNotes;
68478         }
68479
68480         function svgTouch() {
68481           function drawTouch(selection) {
68482             selection.selectAll('.layer-touch').data(['areas', 'lines', 'points', 'turns', 'markers']).enter().append('g').attr('class', function (d) {
68483               return 'layer-touch ' + d;
68484             });
68485           }
68486
68487           return drawTouch;
68488         }
68489
68490         function refresh(selection, node) {
68491           var cr = node.getBoundingClientRect();
68492           var prop = [cr.width, cr.height];
68493           selection.property('__dimensions__', prop);
68494           return prop;
68495         }
68496
68497         function utilGetDimensions(selection, force) {
68498           if (!selection || selection.empty()) {
68499             return [0, 0];
68500           }
68501
68502           var node = selection.node(),
68503               cached = selection.property('__dimensions__');
68504           return !cached || force ? refresh(selection, node) : cached;
68505         }
68506         function utilSetDimensions(selection, dimensions) {
68507           if (!selection || selection.empty()) {
68508             return selection;
68509           }
68510
68511           var node = selection.node();
68512
68513           if (dimensions === null) {
68514             refresh(selection, node);
68515             return selection;
68516           }
68517
68518           return selection.property('__dimensions__', [dimensions[0], dimensions[1]]).attr('width', dimensions[0]).attr('height', dimensions[1]);
68519         }
68520
68521         function svgLayers(projection, context) {
68522           var dispatch = dispatch$8('change');
68523           var svg = select(null);
68524           var _layers = [{
68525             id: 'osm',
68526             layer: svgOsm(projection, context, dispatch)
68527           }, {
68528             id: 'notes',
68529             layer: svgNotes(projection, context, dispatch)
68530           }, {
68531             id: 'data',
68532             layer: svgData(projection, context, dispatch)
68533           }, {
68534             id: 'keepRight',
68535             layer: svgKeepRight(projection, context, dispatch)
68536           }, {
68537             id: 'improveOSM',
68538             layer: svgImproveOSM(projection, context, dispatch)
68539           }, {
68540             id: 'osmose',
68541             layer: svgOsmose(projection, context, dispatch)
68542           }, {
68543             id: 'streetside',
68544             layer: svgStreetside(projection, context, dispatch)
68545           }, {
68546             id: 'mapillary',
68547             layer: svgMapillaryImages(projection, context, dispatch)
68548           }, {
68549             id: 'mapillary-position',
68550             layer: svgMapillaryPosition(projection, context)
68551           }, {
68552             id: 'mapillary-map-features',
68553             layer: svgMapillaryMapFeatures(projection, context, dispatch)
68554           }, {
68555             id: 'mapillary-signs',
68556             layer: svgMapillarySigns(projection, context, dispatch)
68557           }, {
68558             id: 'openstreetcam',
68559             layer: svgOpenstreetcamImages(projection, context, dispatch)
68560           }, {
68561             id: 'debug',
68562             layer: svgDebug(projection, context)
68563           }, {
68564             id: 'geolocate',
68565             layer: svgGeolocate(projection)
68566           }, {
68567             id: 'touch',
68568             layer: svgTouch()
68569           }];
68570
68571           function drawLayers(selection) {
68572             svg = selection.selectAll('.surface').data([0]);
68573             svg = svg.enter().append('svg').attr('class', 'surface').merge(svg);
68574             var defs = svg.selectAll('.surface-defs').data([0]);
68575             defs.enter().append('defs').attr('class', 'surface-defs');
68576             var groups = svg.selectAll('.data-layer').data(_layers);
68577             groups.exit().remove();
68578             groups.enter().append('g').attr('class', function (d) {
68579               return 'data-layer ' + d.id;
68580             }).merge(groups).each(function (d) {
68581               select(this).call(d.layer);
68582             });
68583           }
68584
68585           drawLayers.all = function () {
68586             return _layers;
68587           };
68588
68589           drawLayers.layer = function (id) {
68590             var obj = _layers.find(function (o) {
68591               return o.id === id;
68592             });
68593
68594             return obj && obj.layer;
68595           };
68596
68597           drawLayers.only = function (what) {
68598             var arr = [].concat(what);
68599
68600             var all = _layers.map(function (layer) {
68601               return layer.id;
68602             });
68603
68604             return drawLayers.remove(utilArrayDifference(all, arr));
68605           };
68606
68607           drawLayers.remove = function (what) {
68608             var arr = [].concat(what);
68609             arr.forEach(function (id) {
68610               _layers = _layers.filter(function (o) {
68611                 return o.id !== id;
68612               });
68613             });
68614             dispatch.call('change');
68615             return this;
68616           };
68617
68618           drawLayers.add = function (what) {
68619             var arr = [].concat(what);
68620             arr.forEach(function (obj) {
68621               if ('id' in obj && 'layer' in obj) {
68622                 _layers.push(obj);
68623               }
68624             });
68625             dispatch.call('change');
68626             return this;
68627           };
68628
68629           drawLayers.dimensions = function (val) {
68630             if (!arguments.length) return utilGetDimensions(svg);
68631             utilSetDimensions(svg, val);
68632             return this;
68633           };
68634
68635           return utilRebind(drawLayers, dispatch, 'on');
68636         }
68637
68638         function svgLines(projection, context) {
68639           var detected = utilDetect();
68640           var highway_stack = {
68641             motorway: 0,
68642             motorway_link: 1,
68643             trunk: 2,
68644             trunk_link: 3,
68645             primary: 4,
68646             primary_link: 5,
68647             secondary: 6,
68648             tertiary: 7,
68649             unclassified: 8,
68650             residential: 9,
68651             service: 10,
68652             footway: 11
68653           };
68654
68655           function drawTargets(selection, graph, entities, filter) {
68656             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
68657             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
68658             var getPath = svgPath(projection).geojson;
68659             var activeID = context.activeID();
68660             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
68661
68662             var data = {
68663               targets: [],
68664               nopes: []
68665             };
68666             entities.forEach(function (way) {
68667               var features = svgSegmentWay(way, graph, activeID);
68668               data.targets.push.apply(data.targets, features.passive);
68669               data.nopes.push.apply(data.nopes, features.active);
68670             }); // Targets allow hover and vertex snapping
68671
68672             var targetData = data.targets.filter(getPath);
68673             var targets = selection.selectAll('.line.target-allowed').filter(function (d) {
68674               return filter(d.properties.entity);
68675             }).data(targetData, function key(d) {
68676               return d.id;
68677             }); // exit
68678
68679             targets.exit().remove();
68680
68681             var segmentWasEdited = function segmentWasEdited(d) {
68682               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
68683
68684               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
68685                 return false;
68686               }
68687
68688               return d.properties.nodes.some(function (n) {
68689                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
68690               });
68691             }; // enter/update
68692
68693
68694             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
68695               return 'way line target target-allowed ' + targetClass + d.id;
68696             }).classed('segment-edited', segmentWasEdited); // NOPE
68697
68698             var nopeData = data.nopes.filter(getPath);
68699             var nopes = selection.selectAll('.line.target-nope').filter(function (d) {
68700               return filter(d.properties.entity);
68701             }).data(nopeData, function key(d) {
68702               return d.id;
68703             }); // exit
68704
68705             nopes.exit().remove(); // enter/update
68706
68707             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
68708               return 'way line target target-nope ' + nopeClass + d.id;
68709             }).classed('segment-edited', segmentWasEdited);
68710           }
68711
68712           function drawLines(selection, graph, entities, filter) {
68713             var base = context.history().base();
68714
68715             function waystack(a, b) {
68716               var selected = context.selectedIDs();
68717               var scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0;
68718               var scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
68719
68720               if (a.tags.highway) {
68721                 scoreA -= highway_stack[a.tags.highway];
68722               }
68723
68724               if (b.tags.highway) {
68725                 scoreB -= highway_stack[b.tags.highway];
68726               }
68727
68728               return scoreA - scoreB;
68729             }
68730
68731             function drawLineGroup(selection, klass, isSelected) {
68732               // Note: Don't add `.selected` class in draw modes
68733               var mode = context.mode();
68734               var isDrawing = mode && /^draw/.test(mode.id);
68735               var selectedClass = !isDrawing && isSelected ? 'selected ' : '';
68736               var lines = selection.selectAll('path').filter(filter).data(getPathData(isSelected), osmEntity.key);
68737               lines.exit().remove(); // Optimization: Call expensive TagClasses only on enter selection. This
68738               // works because osmEntity.key is defined to include the entity v attribute.
68739
68740               lines.enter().append('path').attr('class', function (d) {
68741                 var prefix = 'way line'; // if this line isn't styled by its own tags
68742
68743                 if (!d.hasInterestingTags()) {
68744                   var parentRelations = graph.parentRelations(d);
68745                   var parentMultipolygons = parentRelations.filter(function (relation) {
68746                     return relation.isMultipolygon();
68747                   }); // and if it's a member of at least one multipolygon relation
68748
68749                   if (parentMultipolygons.length > 0 && // and only multipolygon relations
68750                   parentRelations.length === parentMultipolygons.length) {
68751                     // then fudge the classes to style this as an area edge
68752                     prefix = 'relation area';
68753                   }
68754                 }
68755
68756                 var oldMPClass = oldMultiPolygonOuters[d.id] ? 'old-multipolygon ' : '';
68757                 return prefix + ' ' + klass + ' ' + selectedClass + oldMPClass + d.id;
68758               }).classed('added', function (d) {
68759                 return !base.entities[d.id];
68760               }).classed('geometry-edited', function (d) {
68761                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
68762               }).classed('retagged', function (d) {
68763                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
68764               }).call(svgTagClasses()).merge(lines).sort(waystack).attr('d', getPath).call(svgTagClasses().tags(svgRelationMemberTags(graph)));
68765               return selection;
68766             }
68767
68768             function getPathData(isSelected) {
68769               return function () {
68770                 var layer = this.parentNode.__data__;
68771                 var data = pathdata[layer] || [];
68772                 return data.filter(function (d) {
68773                   if (isSelected) {
68774                     return context.selectedIDs().indexOf(d.id) !== -1;
68775                   } else {
68776                     return context.selectedIDs().indexOf(d.id) === -1;
68777                   }
68778                 });
68779               };
68780             }
68781
68782             function addMarkers(layergroup, pathclass, groupclass, groupdata, marker) {
68783               var markergroup = layergroup.selectAll('g.' + groupclass).data([pathclass]);
68784               markergroup = markergroup.enter().append('g').attr('class', groupclass).merge(markergroup);
68785               var markers = markergroup.selectAll('path').filter(filter).data(function data() {
68786                 return groupdata[this.parentNode.__data__] || [];
68787               }, function key(d) {
68788                 return [d.id, d.index];
68789               });
68790               markers.exit().remove();
68791               markers = markers.enter().append('path').attr('class', pathclass).merge(markers).attr('marker-mid', marker).attr('d', function (d) {
68792                 return d.d;
68793               });
68794
68795               if (detected.ie) {
68796                 markers.each(function () {
68797                   this.parentNode.insertBefore(this, this);
68798                 });
68799               }
68800             }
68801
68802             var getPath = svgPath(projection, graph);
68803             var ways = [];
68804             var onewaydata = {};
68805             var sideddata = {};
68806             var oldMultiPolygonOuters = {};
68807
68808             for (var i = 0; i < entities.length; i++) {
68809               var entity = entities[i];
68810               var outer = osmOldMultipolygonOuterMember(entity, graph);
68811
68812               if (outer) {
68813                 ways.push(entity.mergeTags(outer.tags));
68814                 oldMultiPolygonOuters[outer.id] = true;
68815               } else if (entity.geometry(graph) === 'line') {
68816                 ways.push(entity);
68817               }
68818             }
68819
68820             ways = ways.filter(getPath);
68821             var pathdata = utilArrayGroupBy(ways, function (way) {
68822               return way.layer();
68823             });
68824             Object.keys(pathdata).forEach(function (k) {
68825               var v = pathdata[k];
68826               var onewayArr = v.filter(function (d) {
68827                 return d.isOneWay();
68828               });
68829               var onewaySegments = svgMarkerSegments(projection, graph, 35, function shouldReverse(entity) {
68830                 return entity.tags.oneway === '-1';
68831               }, function bothDirections(entity) {
68832                 return entity.tags.oneway === 'reversible' || entity.tags.oneway === 'alternating';
68833               });
68834               onewaydata[k] = utilArrayFlatten(onewayArr.map(onewaySegments));
68835               var sidedArr = v.filter(function (d) {
68836                 return d.isSided();
68837               });
68838               var sidedSegments = svgMarkerSegments(projection, graph, 30, function shouldReverse() {
68839                 return false;
68840               }, function bothDirections() {
68841                 return false;
68842               });
68843               sideddata[k] = utilArrayFlatten(sidedArr.map(sidedSegments));
68844             });
68845             var covered = selection.selectAll('.layer-osm.covered'); // under areas
68846
68847             var uncovered = selection.selectAll('.layer-osm.lines'); // over areas
68848
68849             var touchLayer = selection.selectAll('.layer-touch.lines'); // Draw lines..
68850
68851             [covered, uncovered].forEach(function (selection) {
68852               var range = selection === covered ? range$1(-10, 0) : range$1(0, 11);
68853               var layergroup = selection.selectAll('g.layergroup').data(range);
68854               layergroup = layergroup.enter().append('g').attr('class', function (d) {
68855                 return 'layergroup layer' + String(d);
68856               }).merge(layergroup);
68857               layergroup.selectAll('g.linegroup').data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted']).enter().append('g').attr('class', function (d) {
68858                 return 'linegroup line-' + d;
68859               });
68860               layergroup.selectAll('g.line-shadow').call(drawLineGroup, 'shadow', false);
68861               layergroup.selectAll('g.line-casing').call(drawLineGroup, 'casing', false);
68862               layergroup.selectAll('g.line-stroke').call(drawLineGroup, 'stroke', false);
68863               layergroup.selectAll('g.line-shadow-highlighted').call(drawLineGroup, 'shadow', true);
68864               layergroup.selectAll('g.line-casing-highlighted').call(drawLineGroup, 'casing', true);
68865               layergroup.selectAll('g.line-stroke-highlighted').call(drawLineGroup, 'stroke', true);
68866               addMarkers(layergroup, 'oneway', 'onewaygroup', onewaydata, 'url(#ideditor-oneway-marker)');
68867               addMarkers(layergroup, 'sided', 'sidedgroup', sideddata, function marker(d) {
68868                 var category = graph.entity(d.id).sidednessIdentifier();
68869                 return 'url(#ideditor-sided-marker-' + category + ')';
68870               });
68871             }); // Draw touch targets..
68872
68873             touchLayer.call(drawTargets, graph, ways, filter);
68874           }
68875
68876           return drawLines;
68877         }
68878
68879         function svgMidpoints(projection, context) {
68880           var targetRadius = 8;
68881
68882           function drawTargets(selection, graph, entities, filter) {
68883             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
68884             var getTransform = svgPointTransform(projection).geojson;
68885             var data = entities.map(function (midpoint) {
68886               return {
68887                 type: 'Feature',
68888                 id: midpoint.id,
68889                 properties: {
68890                   target: true,
68891                   entity: midpoint
68892                 },
68893                 geometry: {
68894                   type: 'Point',
68895                   coordinates: midpoint.loc
68896                 }
68897               };
68898             });
68899             var targets = selection.selectAll('.midpoint.target').filter(function (d) {
68900               return filter(d.properties.entity);
68901             }).data(data, function key(d) {
68902               return d.id;
68903             }); // exit
68904
68905             targets.exit().remove(); // enter/update
68906
68907             targets.enter().append('circle').attr('r', targetRadius).merge(targets).attr('class', function (d) {
68908               return 'node midpoint target ' + fillClass + d.id;
68909             }).attr('transform', getTransform);
68910           }
68911
68912           function drawMidpoints(selection, graph, entities, filter, extent) {
68913             var drawLayer = selection.selectAll('.layer-osm.points .points-group.midpoints');
68914             var touchLayer = selection.selectAll('.layer-touch.points');
68915             var mode = context.mode();
68916
68917             if (mode && mode.id !== 'select' || !context.map().withinEditableZoom()) {
68918               drawLayer.selectAll('.midpoint').remove();
68919               touchLayer.selectAll('.midpoint.target').remove();
68920               return;
68921             }
68922
68923             var poly = extent.polygon();
68924             var midpoints = {};
68925
68926             for (var i = 0; i < entities.length; i++) {
68927               var entity = entities[i];
68928               if (entity.type !== 'way') continue;
68929               if (!filter(entity)) continue;
68930               if (context.selectedIDs().indexOf(entity.id) < 0) continue;
68931               var nodes = graph.childNodes(entity);
68932
68933               for (var j = 0; j < nodes.length - 1; j++) {
68934                 var a = nodes[j];
68935                 var b = nodes[j + 1];
68936                 var id = [a.id, b.id].sort().join('-');
68937
68938                 if (midpoints[id]) {
68939                   midpoints[id].parents.push(entity);
68940                 } else if (geoVecLength(projection(a.loc), projection(b.loc)) > 40) {
68941                   var point = geoVecInterp(a.loc, b.loc, 0.5);
68942                   var loc = null;
68943
68944                   if (extent.intersects(point)) {
68945                     loc = point;
68946                   } else {
68947                     for (var k = 0; k < 4; k++) {
68948                       point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
68949
68950                       if (point && geoVecLength(projection(a.loc), projection(point)) > 20 && geoVecLength(projection(b.loc), projection(point)) > 20) {
68951                         loc = point;
68952                         break;
68953                       }
68954                     }
68955                   }
68956
68957                   if (loc) {
68958                     midpoints[id] = {
68959                       type: 'midpoint',
68960                       id: id,
68961                       loc: loc,
68962                       edge: [a.id, b.id],
68963                       parents: [entity]
68964                     };
68965                   }
68966                 }
68967               }
68968             }
68969
68970             function midpointFilter(d) {
68971               if (midpoints[d.id]) return true;
68972
68973               for (var i = 0; i < d.parents.length; i++) {
68974                 if (filter(d.parents[i])) {
68975                   return true;
68976                 }
68977               }
68978
68979               return false;
68980             }
68981
68982             var groups = drawLayer.selectAll('.midpoint').filter(midpointFilter).data(Object.values(midpoints), function (d) {
68983               return d.id;
68984             });
68985             groups.exit().remove();
68986             var enter = groups.enter().insert('g', ':first-child').attr('class', 'midpoint');
68987             enter.append('polygon').attr('points', '-6,8 10,0 -6,-8').attr('class', 'shadow');
68988             enter.append('polygon').attr('points', '-3,4 5,0 -3,-4').attr('class', 'fill');
68989             groups = groups.merge(enter).attr('transform', function (d) {
68990               var translate = svgPointTransform(projection);
68991               var a = graph.entity(d.edge[0]);
68992               var b = graph.entity(d.edge[1]);
68993               var angle = geoAngle(a, b, projection) * (180 / Math.PI);
68994               return translate(d) + ' rotate(' + angle + ')';
68995             }).call(svgTagClasses().tags(function (d) {
68996               return d.parents[0].tags;
68997             })); // Propagate data bindings.
68998
68999             groups.select('polygon.shadow');
69000             groups.select('polygon.fill'); // Draw touch targets..
69001
69002             touchLayer.call(drawTargets, graph, Object.values(midpoints), midpointFilter);
69003           }
69004
69005           return drawMidpoints;
69006         }
69007
69008         function svgPoints(projection, context) {
69009           function markerPath(selection, klass) {
69010             selection.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');
69011           }
69012
69013           function sortY(a, b) {
69014             return b.loc[1] - a.loc[1];
69015           } // Avoid exit/enter if we're just moving stuff around.
69016           // The node will get a new version but we only need to run the update selection.
69017
69018
69019           function fastEntityKey(d) {
69020             var mode = context.mode();
69021             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
69022             return isMoving ? d.id : osmEntity.key(d);
69023           }
69024
69025           function drawTargets(selection, graph, entities, filter) {
69026             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
69027             var getTransform = svgPointTransform(projection).geojson;
69028             var activeID = context.activeID();
69029             var data = [];
69030             entities.forEach(function (node) {
69031               if (activeID === node.id) return; // draw no target on the activeID
69032
69033               data.push({
69034                 type: 'Feature',
69035                 id: node.id,
69036                 properties: {
69037                   target: true,
69038                   entity: node
69039                 },
69040                 geometry: node.asGeoJSON()
69041               });
69042             });
69043             var targets = selection.selectAll('.point.target').filter(function (d) {
69044               return filter(d.properties.entity);
69045             }).data(data, function key(d) {
69046               return d.id;
69047             }); // exit
69048
69049             targets.exit().remove(); // enter/update
69050
69051             targets.enter().append('rect').attr('x', -10).attr('y', -26).attr('width', 20).attr('height', 30).merge(targets).attr('class', function (d) {
69052               return 'node point target ' + fillClass + d.id;
69053             }).attr('transform', getTransform);
69054           }
69055
69056           function drawPoints(selection, graph, entities, filter) {
69057             var wireframe = context.surface().classed('fill-wireframe');
69058             var zoom = geoScaleToZoom(projection.scale());
69059             var base = context.history().base(); // Points with a direction will render as vertices at higher zooms..
69060
69061             function renderAsPoint(entity) {
69062               return entity.geometry(graph) === 'point' && !(zoom >= 18 && entity.directions(graph, projection).length);
69063             } // All points will render as vertices in wireframe mode too..
69064
69065
69066             var points = wireframe ? [] : entities.filter(renderAsPoint);
69067             points.sort(sortY);
69068             var drawLayer = selection.selectAll('.layer-osm.points .points-group.points');
69069             var touchLayer = selection.selectAll('.layer-touch.points'); // Draw points..
69070
69071             var groups = drawLayer.selectAll('g.point').filter(filter).data(points, fastEntityKey);
69072             groups.exit().remove();
69073             var enter = groups.enter().append('g').attr('class', function (d) {
69074               return 'node point ' + d.id;
69075             }).order();
69076             enter.append('path').call(markerPath, 'shadow');
69077             enter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
69078             enter.append('path').call(markerPath, 'stroke');
69079             enter.append('use').attr('transform', 'translate(-5, -19)').attr('class', 'icon').attr('width', '11px').attr('height', '11px');
69080             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('added', function (d) {
69081               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
69082             }).classed('moved', function (d) {
69083               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
69084             }).classed('retagged', function (d) {
69085               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
69086             }).call(svgTagClasses());
69087             groups.select('.shadow'); // propagate bound data
69088
69089             groups.select('.stroke'); // propagate bound data
69090
69091             groups.select('.icon') // propagate bound data
69092             .attr('xlink:href', function (entity) {
69093               var preset = _mainPresetIndex.match(entity, graph);
69094               var picon = preset && preset.icon;
69095
69096               if (!picon) {
69097                 return '';
69098               } else {
69099                 var isMaki = /^maki-/.test(picon);
69100                 return '#' + picon + (isMaki ? '-11' : '');
69101               }
69102             }); // Draw touch targets..
69103
69104             touchLayer.call(drawTargets, graph, points, filter);
69105           }
69106
69107           return drawPoints;
69108         }
69109
69110         function svgTurns(projection, context) {
69111           function icon(turn) {
69112             var u = turn.u ? '-u' : '';
69113             if (turn.no) return '#iD-turn-no' + u;
69114             if (turn.only) return '#iD-turn-only' + u;
69115             return '#iD-turn-yes' + u;
69116           }
69117
69118           function drawTurns(selection, graph, turns) {
69119             function turnTransform(d) {
69120               var pxRadius = 50;
69121               var toWay = graph.entity(d.to.way);
69122               var toPoints = graph.childNodes(toWay).map(function (n) {
69123                 return n.loc;
69124               }).map(projection);
69125               var toLength = geoPathLength(toPoints);
69126               var mid = toLength / 2; // midpoint of destination way
69127
69128               var toNode = graph.entity(d.to.node);
69129               var toVertex = graph.entity(d.to.vertex);
69130               var a = geoAngle(toVertex, toNode, projection);
69131               var o = projection(toVertex.loc);
69132               var r = d.u ? 0 // u-turn: no radius
69133               : !toWay.__via ? pxRadius // leaf way: put marker at pxRadius
69134               : Math.min(mid, pxRadius); // via way: prefer pxRadius, fallback to mid for very short ways
69135
69136               return 'translate(' + (r * Math.cos(a) + o[0]) + ',' + (r * Math.sin(a) + o[1]) + ') ' + 'rotate(' + a * 180 / Math.PI + ')';
69137             }
69138
69139             var drawLayer = selection.selectAll('.layer-osm.points .points-group.turns');
69140             var touchLayer = selection.selectAll('.layer-touch.turns'); // Draw turns..
69141
69142             var groups = drawLayer.selectAll('g.turn').data(turns, function (d) {
69143               return d.key;
69144             }); // exit
69145
69146             groups.exit().remove(); // enter
69147
69148             var groupsEnter = groups.enter().append('g').attr('class', function (d) {
69149               return 'turn ' + d.key;
69150             });
69151             var turnsEnter = groupsEnter.filter(function (d) {
69152               return !d.u;
69153             });
69154             turnsEnter.append('rect').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
69155             turnsEnter.append('use').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
69156             var uEnter = groupsEnter.filter(function (d) {
69157               return d.u;
69158             });
69159             uEnter.append('circle').attr('r', '16');
69160             uEnter.append('use').attr('transform', 'translate(-16, -16)').attr('width', '32').attr('height', '32'); // update
69161
69162             groups = groups.merge(groupsEnter).attr('opacity', function (d) {
69163               return d.direct === false ? '0.7' : null;
69164             }).attr('transform', turnTransform);
69165             groups.select('use').attr('xlink:href', icon);
69166             groups.select('rect'); // propagate bound data
69167
69168             groups.select('circle'); // propagate bound data
69169             // Draw touch targets..
69170
69171             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
69172             groups = touchLayer.selectAll('g.turn').data(turns, function (d) {
69173               return d.key;
69174             }); // exit
69175
69176             groups.exit().remove(); // enter
69177
69178             groupsEnter = groups.enter().append('g').attr('class', function (d) {
69179               return 'turn ' + d.key;
69180             });
69181             turnsEnter = groupsEnter.filter(function (d) {
69182               return !d.u;
69183             });
69184             turnsEnter.append('rect').attr('class', 'target ' + fillClass).attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
69185             uEnter = groupsEnter.filter(function (d) {
69186               return d.u;
69187             });
69188             uEnter.append('circle').attr('class', 'target ' + fillClass).attr('r', '16'); // update
69189
69190             groups = groups.merge(groupsEnter).attr('transform', turnTransform);
69191             groups.select('rect'); // propagate bound data
69192
69193             groups.select('circle'); // propagate bound data
69194
69195             return this;
69196           }
69197
69198           return drawTurns;
69199         }
69200
69201         function svgVertices(projection, context) {
69202           var radiuses = {
69203             //       z16-, z17,   z18+,  w/icon
69204             shadow: [6, 7.5, 7.5, 12],
69205             stroke: [2.5, 3.5, 3.5, 8],
69206             fill: [1, 1.5, 1.5, 1.5]
69207           };
69208
69209           var _currHoverTarget;
69210
69211           var _currPersistent = {};
69212           var _currHover = {};
69213           var _prevHover = {};
69214           var _currSelected = {};
69215           var _prevSelected = {};
69216           var _radii = {};
69217
69218           function sortY(a, b) {
69219             return b.loc[1] - a.loc[1];
69220           } // Avoid exit/enter if we're just moving stuff around.
69221           // The node will get a new version but we only need to run the update selection.
69222
69223
69224           function fastEntityKey(d) {
69225             var mode = context.mode();
69226             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
69227             return isMoving ? d.id : osmEntity.key(d);
69228           }
69229
69230           function draw(selection, graph, vertices, sets, filter) {
69231             sets = sets || {
69232               selected: {},
69233               important: {},
69234               hovered: {}
69235             };
69236             var icons = {};
69237             var directions = {};
69238             var wireframe = context.surface().classed('fill-wireframe');
69239             var zoom = geoScaleToZoom(projection.scale());
69240             var z = zoom < 17 ? 0 : zoom < 18 ? 1 : 2;
69241             var activeID = context.activeID();
69242             var base = context.history().base();
69243
69244             function getIcon(d) {
69245               // always check latest entity, as fastEntityKey avoids enter/exit now
69246               var entity = graph.entity(d.id);
69247               if (entity.id in icons) return icons[entity.id];
69248               icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
69249               return icons[entity.id];
69250             } // memoize directions results, return false for empty arrays (for use in filter)
69251
69252
69253             function getDirections(entity) {
69254               if (entity.id in directions) return directions[entity.id];
69255               var angles = entity.directions(graph, projection);
69256               directions[entity.id] = angles.length ? angles : false;
69257               return angles;
69258             }
69259
69260             function updateAttributes(selection) {
69261               ['shadow', 'stroke', 'fill'].forEach(function (klass) {
69262                 var rads = radiuses[klass];
69263                 selection.selectAll('.' + klass).each(function (entity) {
69264                   var i = z && getIcon(entity);
69265                   var r = rads[i ? 3 : z]; // slightly increase the size of unconnected endpoints #3775
69266
69267                   if (entity.id !== activeID && entity.isEndpoint(graph) && !entity.isConnected(graph)) {
69268                     r += 1.5;
69269                   }
69270
69271                   if (klass === 'shadow') {
69272                     // remember this value, so we don't need to
69273                     _radii[entity.id] = r; // recompute it when we draw the touch targets
69274                   }
69275
69276                   select(this).attr('r', r).attr('visibility', i && klass === 'fill' ? 'hidden' : null);
69277                 });
69278               });
69279             }
69280
69281             vertices.sort(sortY);
69282             var groups = selection.selectAll('g.vertex').filter(filter).data(vertices, fastEntityKey); // exit
69283
69284             groups.exit().remove(); // enter
69285
69286             var enter = groups.enter().append('g').attr('class', function (d) {
69287               return 'node vertex ' + d.id;
69288             }).order();
69289             enter.append('circle').attr('class', 'shadow');
69290             enter.append('circle').attr('class', 'stroke'); // Vertices with tags get a fill.
69291
69292             enter.filter(function (d) {
69293               return d.hasInterestingTags();
69294             }).append('circle').attr('class', 'fill'); // update
69295
69296             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('sibling', function (d) {
69297               return d.id in sets.selected;
69298             }).classed('shared', function (d) {
69299               return graph.isShared(d);
69300             }).classed('endpoint', function (d) {
69301               return d.isEndpoint(graph);
69302             }).classed('added', function (d) {
69303               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
69304             }).classed('moved', function (d) {
69305               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
69306             }).classed('retagged', function (d) {
69307               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
69308             }).call(updateAttributes); // Vertices with icons get a `use`.
69309
69310             var iconUse = groups.selectAll('.icon').data(function data(d) {
69311               return zoom >= 17 && getIcon(d) ? [d] : [];
69312             }, fastEntityKey); // exit
69313
69314             iconUse.exit().remove(); // enter
69315
69316             iconUse.enter().append('use').attr('class', 'icon').attr('width', '11px').attr('height', '11px').attr('transform', 'translate(-5.5, -5.5)').attr('xlink:href', function (d) {
69317               var picon = getIcon(d);
69318               var isMaki = /^maki-/.test(picon);
69319               return '#' + picon + (isMaki ? '-11' : '');
69320             }); // Vertices with directions get viewfields
69321
69322             var dgroups = groups.selectAll('.viewfieldgroup').data(function data(d) {
69323               return zoom >= 18 && getDirections(d) ? [d] : [];
69324             }, fastEntityKey); // exit
69325
69326             dgroups.exit().remove(); // enter/update
69327
69328             dgroups = dgroups.enter().insert('g', '.shadow').attr('class', 'viewfieldgroup').merge(dgroups);
69329             var viewfields = dgroups.selectAll('.viewfield').data(getDirections, function key(d) {
69330               return osmEntity.key(d);
69331             }); // exit
69332
69333             viewfields.exit().remove(); // enter/update
69334
69335             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) {
69336               return 'rotate(' + d + ')';
69337             });
69338           }
69339
69340           function drawTargets(selection, graph, entities, filter) {
69341             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
69342             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
69343             var getTransform = svgPointTransform(projection).geojson;
69344             var activeID = context.activeID();
69345             var data = {
69346               targets: [],
69347               nopes: []
69348             };
69349             entities.forEach(function (node) {
69350               if (activeID === node.id) return; // draw no target on the activeID
69351
69352               var vertexType = svgPassiveVertex(node, graph, activeID);
69353
69354               if (vertexType !== 0) {
69355                 // passive or adjacent - allow to connect
69356                 data.targets.push({
69357                   type: 'Feature',
69358                   id: node.id,
69359                   properties: {
69360                     target: true,
69361                     entity: node
69362                   },
69363                   geometry: node.asGeoJSON()
69364                 });
69365               } else {
69366                 data.nopes.push({
69367                   type: 'Feature',
69368                   id: node.id + '-nope',
69369                   properties: {
69370                     nope: true,
69371                     target: true,
69372                     entity: node
69373                   },
69374                   geometry: node.asGeoJSON()
69375                 });
69376               }
69377             }); // Targets allow hover and vertex snapping
69378
69379             var targets = selection.selectAll('.vertex.target-allowed').filter(function (d) {
69380               return filter(d.properties.entity);
69381             }).data(data.targets, function key(d) {
69382               return d.id;
69383             }); // exit
69384
69385             targets.exit().remove(); // enter/update
69386
69387             targets.enter().append('circle').attr('r', function (d) {
69388               return _radii[d.id] || radiuses.shadow[3];
69389             }).merge(targets).attr('class', function (d) {
69390               return 'node vertex target target-allowed ' + targetClass + d.id;
69391             }).attr('transform', getTransform); // NOPE
69392
69393             var nopes = selection.selectAll('.vertex.target-nope').filter(function (d) {
69394               return filter(d.properties.entity);
69395             }).data(data.nopes, function key(d) {
69396               return d.id;
69397             }); // exit
69398
69399             nopes.exit().remove(); // enter/update
69400
69401             nopes.enter().append('circle').attr('r', function (d) {
69402               return _radii[d.properties.entity.id] || radiuses.shadow[3];
69403             }).merge(nopes).attr('class', function (d) {
69404               return 'node vertex target target-nope ' + nopeClass + d.id;
69405             }).attr('transform', getTransform);
69406           } // Points can also render as vertices:
69407           // 1. in wireframe mode or
69408           // 2. at higher zooms if they have a direction
69409
69410
69411           function renderAsVertex(entity, graph, wireframe, zoom) {
69412             var geometry = entity.geometry(graph);
69413             return geometry === 'vertex' || geometry === 'point' && (wireframe || zoom >= 18 && entity.directions(graph, projection).length);
69414           }
69415
69416           function isEditedNode(node, base, head) {
69417             var baseNode = base.entities[node.id];
69418             var headNode = head.entities[node.id];
69419             return !headNode || !baseNode || !fastDeepEqual(headNode.tags, baseNode.tags) || !fastDeepEqual(headNode.loc, baseNode.loc);
69420           }
69421
69422           function getSiblingAndChildVertices(ids, graph, wireframe, zoom) {
69423             var results = {};
69424             var seenIds = {};
69425
69426             function addChildVertices(entity) {
69427               // avoid redundant work and infinite recursion of circular relations
69428               if (seenIds[entity.id]) return;
69429               seenIds[entity.id] = true;
69430               var geometry = entity.geometry(graph);
69431
69432               if (!context.features().isHiddenFeature(entity, graph, geometry)) {
69433                 var i;
69434
69435                 if (entity.type === 'way') {
69436                   for (i = 0; i < entity.nodes.length; i++) {
69437                     var child = graph.hasEntity(entity.nodes[i]);
69438
69439                     if (child) {
69440                       addChildVertices(child);
69441                     }
69442                   }
69443                 } else if (entity.type === 'relation') {
69444                   for (i = 0; i < entity.members.length; i++) {
69445                     var member = graph.hasEntity(entity.members[i].id);
69446
69447                     if (member) {
69448                       addChildVertices(member);
69449                     }
69450                   }
69451                 } else if (renderAsVertex(entity, graph, wireframe, zoom)) {
69452                   results[entity.id] = entity;
69453                 }
69454               }
69455             }
69456
69457             ids.forEach(function (id) {
69458               var entity = graph.hasEntity(id);
69459               if (!entity) return;
69460
69461               if (entity.type === 'node') {
69462                 if (renderAsVertex(entity, graph, wireframe, zoom)) {
69463                   results[entity.id] = entity;
69464                   graph.parentWays(entity).forEach(function (entity) {
69465                     addChildVertices(entity);
69466                   });
69467                 }
69468               } else {
69469                 // way, relation
69470                 addChildVertices(entity);
69471               }
69472             });
69473             return results;
69474           }
69475
69476           function drawVertices(selection, graph, entities, filter, extent, fullRedraw) {
69477             var wireframe = context.surface().classed('fill-wireframe');
69478             var visualDiff = context.surface().classed('highlight-edited');
69479             var zoom = geoScaleToZoom(projection.scale());
69480             var mode = context.mode();
69481             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
69482             var base = context.history().base();
69483             var drawLayer = selection.selectAll('.layer-osm.points .points-group.vertices');
69484             var touchLayer = selection.selectAll('.layer-touch.points');
69485
69486             if (fullRedraw) {
69487               _currPersistent = {};
69488               _radii = {};
69489             } // Collect important vertices from the `entities` list..
69490             // (during a partial redraw, it will not contain everything)
69491
69492
69493             for (var i = 0; i < entities.length; i++) {
69494               var entity = entities[i];
69495               var geometry = entity.geometry(graph);
69496               var keep = false; // a point that looks like a vertex..
69497
69498               if (geometry === 'point' && renderAsVertex(entity, graph, wireframe, zoom)) {
69499                 _currPersistent[entity.id] = entity;
69500                 keep = true; // a vertex of some importance..
69501               } else if (geometry === 'vertex' && (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || visualDiff && isEditedNode(entity, base, graph))) {
69502                 _currPersistent[entity.id] = entity;
69503                 keep = true;
69504               } // whatever this is, it's not a persistent vertex..
69505
69506
69507               if (!keep && !fullRedraw) {
69508                 delete _currPersistent[entity.id];
69509               }
69510             } // 3 sets of vertices to consider:
69511
69512
69513             var sets = {
69514               persistent: _currPersistent,
69515               // persistent = important vertices (render always)
69516               selected: _currSelected,
69517               // selected + siblings of selected (render always)
69518               hovered: _currHover // hovered + siblings of hovered (render only in draw modes)
69519
69520             };
69521             var all = Object.assign({}, isMoving ? _currHover : {}, _currSelected, _currPersistent); // Draw the vertices..
69522             // The filter function controls the scope of what objects d3 will touch (exit/enter/update)
69523             // Adjust the filter function to expand the scope beyond whatever entities were passed in.
69524
69525             var filterRendered = function filterRendered(d) {
69526               return d.id in _currPersistent || d.id in _currSelected || d.id in _currHover || filter(d);
69527             };
69528
69529             drawLayer.call(draw, graph, currentVisible(all), sets, filterRendered); // Draw touch targets..
69530             // When drawing, render all targets (not just those affected by a partial redraw)
69531
69532             var filterTouch = function filterTouch(d) {
69533               return isMoving ? true : filterRendered(d);
69534             };
69535
69536             touchLayer.call(drawTargets, graph, currentVisible(all), filterTouch);
69537
69538             function currentVisible(which) {
69539               return Object.keys(which).map(graph.hasEntity, graph) // the current version of this entity
69540               .filter(function (entity) {
69541                 return entity && entity.intersects(extent, graph);
69542               });
69543             }
69544           } // partial redraw - only update the selected items..
69545
69546
69547           drawVertices.drawSelected = function (selection, graph, extent) {
69548             var wireframe = context.surface().classed('fill-wireframe');
69549             var zoom = geoScaleToZoom(projection.scale());
69550             _prevSelected = _currSelected || {};
69551
69552             if (context.map().isInWideSelection()) {
69553               _currSelected = {};
69554               context.selectedIDs().forEach(function (id) {
69555                 var entity = graph.hasEntity(id);
69556                 if (!entity) return;
69557
69558                 if (entity.type === 'node') {
69559                   if (renderAsVertex(entity, graph, wireframe, zoom)) {
69560                     _currSelected[entity.id] = entity;
69561                   }
69562                 }
69563               });
69564             } else {
69565               _currSelected = getSiblingAndChildVertices(context.selectedIDs(), graph, wireframe, zoom);
69566             } // note that drawVertices will add `_currSelected` automatically if needed..
69567
69568
69569             var filter = function filter(d) {
69570               return d.id in _prevSelected;
69571             };
69572
69573             drawVertices(selection, graph, Object.values(_prevSelected), filter, extent, false);
69574           }; // partial redraw - only update the hovered items..
69575
69576
69577           drawVertices.drawHover = function (selection, graph, target, extent) {
69578             if (target === _currHoverTarget) return; // continue only if something changed
69579
69580             var wireframe = context.surface().classed('fill-wireframe');
69581             var zoom = geoScaleToZoom(projection.scale());
69582             _prevHover = _currHover || {};
69583             _currHoverTarget = target;
69584             var entity = target && target.properties && target.properties.entity;
69585
69586             if (entity) {
69587               _currHover = getSiblingAndChildVertices([entity.id], graph, wireframe, zoom);
69588             } else {
69589               _currHover = {};
69590             } // note that drawVertices will add `_currHover` automatically if needed..
69591
69592
69593             var filter = function filter(d) {
69594               return d.id in _prevHover;
69595             };
69596
69597             drawVertices(selection, graph, Object.values(_prevHover), filter, extent, false);
69598           };
69599
69600           return drawVertices;
69601         }
69602
69603         function utilBindOnce(target, type, listener, capture) {
69604           var typeOnce = type + '.once';
69605
69606           function one() {
69607             target.on(typeOnce, null);
69608             listener.apply(this, arguments);
69609           }
69610
69611           target.on(typeOnce, one, capture);
69612           return this;
69613         }
69614
69615         function defaultFilter(d3_event) {
69616           return !d3_event.ctrlKey && !d3_event.button;
69617         }
69618
69619         function defaultExtent() {
69620           var e = this;
69621
69622           if (e instanceof SVGElement) {
69623             e = e.ownerSVGElement || e;
69624
69625             if (e.hasAttribute('viewBox')) {
69626               e = e.viewBox.baseVal;
69627               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
69628             }
69629
69630             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
69631           }
69632
69633           return [[0, 0], [e.clientWidth, e.clientHeight]];
69634         }
69635
69636         function defaultWheelDelta(d3_event) {
69637           return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 0.002);
69638         }
69639
69640         function defaultConstrain(transform, extent, translateExtent) {
69641           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
69642               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
69643               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
69644               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
69645           return transform.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));
69646         }
69647
69648         function utilZoomPan() {
69649           var filter = defaultFilter,
69650               extent = defaultExtent,
69651               constrain = defaultConstrain,
69652               wheelDelta = defaultWheelDelta,
69653               scaleExtent = [0, Infinity],
69654               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
69655               interpolate = interpolateZoom,
69656               dispatch = dispatch$8('start', 'zoom', 'end'),
69657               _wheelDelay = 150,
69658               _transform = identity$2,
69659               _activeGesture;
69660
69661           function zoom(selection) {
69662             selection.on('pointerdown.zoom', pointerdown).on('wheel.zoom', wheeled).style('touch-action', 'none').style('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
69663             select(window).on('pointermove.zoompan', pointermove).on('pointerup.zoompan pointercancel.zoompan', pointerup);
69664           }
69665
69666           zoom.transform = function (collection, transform, point) {
69667             var selection = collection.selection ? collection.selection() : collection;
69668
69669             if (collection !== selection) {
69670               schedule(collection, transform, point);
69671             } else {
69672               selection.interrupt().each(function () {
69673                 gesture(this, arguments).start(null).zoom(null, null, typeof transform === 'function' ? transform.apply(this, arguments) : transform).end(null);
69674               });
69675             }
69676           };
69677
69678           zoom.scaleBy = function (selection, k, p) {
69679             zoom.scaleTo(selection, function () {
69680               var k0 = _transform.k,
69681                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
69682               return k0 * k1;
69683             }, p);
69684           };
69685
69686           zoom.scaleTo = function (selection, k, p) {
69687             zoom.transform(selection, function () {
69688               var e = extent.apply(this, arguments),
69689                   t0 = _transform,
69690                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p,
69691                   p1 = t0.invert(p0),
69692                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
69693               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
69694             }, p);
69695           };
69696
69697           zoom.translateBy = function (selection, x, y) {
69698             zoom.transform(selection, function () {
69699               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);
69700             });
69701           };
69702
69703           zoom.translateTo = function (selection, x, y, p) {
69704             zoom.transform(selection, function () {
69705               var e = extent.apply(this, arguments),
69706                   t = _transform,
69707                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p;
69708               return constrain(identity$2.translate(p0[0], p0[1]).scale(t.k).translate(typeof x === 'function' ? -x.apply(this, arguments) : -x, typeof y === 'function' ? -y.apply(this, arguments) : -y), e, translateExtent);
69709             }, p);
69710           };
69711
69712           function scale(transform, k) {
69713             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
69714             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
69715           }
69716
69717           function translate(transform, p0, p1) {
69718             var x = p0[0] - p1[0] * transform.k,
69719                 y = p0[1] - p1[1] * transform.k;
69720             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
69721           }
69722
69723           function centroid(extent) {
69724             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
69725           }
69726
69727           function schedule(transition, transform, point) {
69728             transition.on('start.zoom', function () {
69729               gesture(this, arguments).start(null);
69730             }).on('interrupt.zoom end.zoom', function () {
69731               gesture(this, arguments).end(null);
69732             }).tween('zoom', function () {
69733               var that = this,
69734                   args = arguments,
69735                   g = gesture(that, args),
69736                   e = extent.apply(that, args),
69737                   p = !point ? centroid(e) : typeof point === 'function' ? point.apply(that, args) : point,
69738                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
69739                   a = _transform,
69740                   b = typeof transform === 'function' ? transform.apply(that, args) : transform,
69741                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
69742               return function (t) {
69743                 if (t === 1) {
69744                   // Avoid rounding error on end.
69745                   t = b;
69746                 } else {
69747                   var l = i(t);
69748                   var k = w / l[2];
69749                   t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
69750                 }
69751
69752                 g.zoom(null, null, t);
69753               };
69754             });
69755           }
69756
69757           function gesture(that, args, clean) {
69758             return !clean && _activeGesture || new Gesture(that, args);
69759           }
69760
69761           function Gesture(that, args) {
69762             this.that = that;
69763             this.args = args;
69764             this.active = 0;
69765             this.extent = extent.apply(that, args);
69766           }
69767
69768           Gesture.prototype = {
69769             start: function start(d3_event) {
69770               if (++this.active === 1) {
69771                 _activeGesture = this;
69772                 dispatch.call('start', this, d3_event);
69773               }
69774
69775               return this;
69776             },
69777             zoom: function zoom(d3_event, key, transform) {
69778               if (this.mouse && key !== 'mouse') this.mouse[1] = transform.invert(this.mouse[0]);
69779               if (this.pointer0 && key !== 'touch') this.pointer0[1] = transform.invert(this.pointer0[0]);
69780               if (this.pointer1 && key !== 'touch') this.pointer1[1] = transform.invert(this.pointer1[0]);
69781               _transform = transform;
69782               dispatch.call('zoom', this, d3_event, key, transform);
69783               return this;
69784             },
69785             end: function end(d3_event) {
69786               if (--this.active === 0) {
69787                 _activeGesture = null;
69788                 dispatch.call('end', this, d3_event);
69789               }
69790
69791               return this;
69792             }
69793           };
69794
69795           function wheeled(d3_event) {
69796             if (!filter.apply(this, arguments)) return;
69797             var g = gesture(this, arguments),
69798                 t = _transform,
69799                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
69800                 p = utilFastMouse(this)(d3_event); // If the mouse is in the same location as before, reuse it.
69801             // If there were recent wheel events, reset the wheel idle timeout.
69802
69803             if (g.wheel) {
69804               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
69805                 g.mouse[1] = t.invert(g.mouse[0] = p);
69806               }
69807
69808               clearTimeout(g.wheel); // Otherwise, capture the mouse point and location at the start.
69809             } else {
69810               g.mouse = [p, t.invert(p)];
69811               interrupt(this);
69812               g.start(d3_event);
69813             }
69814
69815             d3_event.preventDefault();
69816             d3_event.stopImmediatePropagation();
69817             g.wheel = setTimeout(wheelidled, _wheelDelay);
69818             g.zoom(d3_event, 'mouse', constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
69819
69820             function wheelidled() {
69821               g.wheel = null;
69822               g.end(d3_event);
69823             }
69824           }
69825
69826           var _downPointerIDs = new Set();
69827
69828           var _pointerLocGetter;
69829
69830           function pointerdown(d3_event) {
69831             _downPointerIDs.add(d3_event.pointerId);
69832
69833             if (!filter.apply(this, arguments)) return;
69834             var g = gesture(this, arguments, _downPointerIDs.size === 1);
69835             var started;
69836             d3_event.stopImmediatePropagation();
69837             _pointerLocGetter = utilFastMouse(this);
69838
69839             var loc = _pointerLocGetter(d3_event);
69840
69841             var p = [loc, _transform.invert(loc), d3_event.pointerId];
69842
69843             if (!g.pointer0) {
69844               g.pointer0 = p;
69845               started = true;
69846             } else if (!g.pointer1 && g.pointer0[2] !== p[2]) {
69847               g.pointer1 = p;
69848             }
69849
69850             if (started) {
69851               interrupt(this);
69852               g.start(d3_event);
69853             }
69854           }
69855
69856           function pointermove(d3_event) {
69857             if (!_downPointerIDs.has(d3_event.pointerId)) return;
69858             if (!_activeGesture || !_pointerLocGetter) return;
69859             var g = gesture(this, arguments);
69860             var isPointer0 = g.pointer0 && g.pointer0[2] === d3_event.pointerId;
69861             var isPointer1 = !isPointer0 && g.pointer1 && g.pointer1[2] === d3_event.pointerId;
69862
69863             if ((isPointer0 || isPointer1) && 'buttons' in d3_event && !d3_event.buttons) {
69864               // The pointer went up without ending the gesture somehow, e.g.
69865               // a down mouse was moved off the map and released. End it here.
69866               if (g.pointer0) _downPointerIDs["delete"](g.pointer0[2]);
69867               if (g.pointer1) _downPointerIDs["delete"](g.pointer1[2]);
69868               g.end(d3_event);
69869               return;
69870             }
69871
69872             d3_event.preventDefault();
69873             d3_event.stopImmediatePropagation();
69874
69875             var loc = _pointerLocGetter(d3_event);
69876
69877             var t, p, l;
69878             if (isPointer0) g.pointer0[0] = loc;else if (isPointer1) g.pointer1[0] = loc;
69879             t = _transform;
69880
69881             if (g.pointer1) {
69882               var p0 = g.pointer0[0],
69883                   l0 = g.pointer0[1],
69884                   p1 = g.pointer1[0],
69885                   l1 = g.pointer1[1],
69886                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
69887                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
69888               t = scale(t, Math.sqrt(dp / dl));
69889               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
69890               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
69891             } else if (g.pointer0) {
69892               p = g.pointer0[0];
69893               l = g.pointer0[1];
69894             } else {
69895               return;
69896             }
69897
69898             g.zoom(d3_event, 'touch', constrain(translate(t, p, l), g.extent, translateExtent));
69899           }
69900
69901           function pointerup(d3_event) {
69902             if (!_downPointerIDs.has(d3_event.pointerId)) return;
69903
69904             _downPointerIDs["delete"](d3_event.pointerId);
69905
69906             if (!_activeGesture) return;
69907             var g = gesture(this, arguments);
69908             d3_event.stopImmediatePropagation();
69909             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;
69910
69911             if (g.pointer1 && !g.pointer0) {
69912               g.pointer0 = g.pointer1;
69913               delete g.pointer1;
69914             }
69915
69916             if (g.pointer0) {
69917               g.pointer0[1] = _transform.invert(g.pointer0[0]);
69918             } else {
69919               g.end(d3_event);
69920             }
69921           }
69922
69923           zoom.wheelDelta = function (_) {
69924             return arguments.length ? (wheelDelta = utilFunctor(+_), zoom) : wheelDelta;
69925           };
69926
69927           zoom.filter = function (_) {
69928             return arguments.length ? (filter = utilFunctor(!!_), zoom) : filter;
69929           };
69930
69931           zoom.extent = function (_) {
69932             return arguments.length ? (extent = utilFunctor([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
69933           };
69934
69935           zoom.scaleExtent = function (_) {
69936             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
69937           };
69938
69939           zoom.translateExtent = function (_) {
69940             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]]];
69941           };
69942
69943           zoom.constrain = function (_) {
69944             return arguments.length ? (constrain = _, zoom) : constrain;
69945           };
69946
69947           zoom.interpolate = function (_) {
69948             return arguments.length ? (interpolate = _, zoom) : interpolate;
69949           };
69950
69951           zoom._transform = function (_) {
69952             return arguments.length ? (_transform = _, zoom) : _transform;
69953           };
69954
69955           return utilRebind(zoom, dispatch, 'on');
69956         }
69957
69958         // if pointer events are supported. Falls back to default `dblclick` event.
69959
69960         function utilDoubleUp() {
69961           var dispatch = dispatch$8('doubleUp');
69962           var _maxTimespan = 500; // milliseconds
69963
69964           var _maxDistance = 20; // web pixels; be somewhat generous to account for touch devices
69965
69966           var _pointer; // object representing the pointer that could trigger double up
69967
69968
69969           function pointerIsValidFor(loc) {
69970             // second pointerup must occur within a small timeframe after the first pointerdown
69971             return new Date().getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
69972             geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
69973           }
69974
69975           function pointerdown(d3_event) {
69976             // ignore right-click
69977             if (d3_event.ctrlKey || d3_event.button === 2) return;
69978             var loc = [d3_event.clientX, d3_event.clientY]; // Don't rely on pointerId here since it can change between pointerdown
69979             // events on touch devices
69980
69981             if (_pointer && !pointerIsValidFor(loc)) {
69982               // if this pointer is no longer valid, clear it so another can be started
69983               _pointer = undefined;
69984             }
69985
69986             if (!_pointer) {
69987               _pointer = {
69988                 startLoc: loc,
69989                 startTime: new Date().getTime(),
69990                 upCount: 0,
69991                 pointerId: d3_event.pointerId
69992               };
69993             } else {
69994               // double down
69995               _pointer.pointerId = d3_event.pointerId;
69996             }
69997           }
69998
69999           function pointerup(d3_event) {
70000             // ignore right-click
70001             if (d3_event.ctrlKey || d3_event.button === 2) return;
70002             if (!_pointer || _pointer.pointerId !== d3_event.pointerId) return;
70003             _pointer.upCount += 1;
70004
70005             if (_pointer.upCount === 2) {
70006               // double up!
70007               var loc = [d3_event.clientX, d3_event.clientY];
70008
70009               if (pointerIsValidFor(loc)) {
70010                 var locInThis = utilFastMouse(this)(d3_event);
70011                 dispatch.call('doubleUp', this, d3_event, locInThis);
70012               } // clear the pointer info in any case
70013
70014
70015               _pointer = undefined;
70016             }
70017           }
70018
70019           function doubleUp(selection) {
70020             if ('PointerEvent' in window) {
70021               // dblclick isn't well supported on touch devices so manually use
70022               // pointer events if they're available
70023               selection.on('pointerdown.doubleUp', pointerdown).on('pointerup.doubleUp', pointerup);
70024             } else {
70025               // fallback to dblclick
70026               selection.on('dblclick.doubleUp', function (d3_event) {
70027                 dispatch.call('doubleUp', this, d3_event, utilFastMouse(this)(d3_event));
70028               });
70029             }
70030           }
70031
70032           doubleUp.off = function (selection) {
70033             selection.on('pointerdown.doubleUp', null).on('pointerup.doubleUp', null).on('dblclick.doubleUp', null);
70034           };
70035
70036           return utilRebind(doubleUp, dispatch, 'on');
70037         }
70038
70039         var TILESIZE = 256;
70040         var minZoom = 2;
70041         var maxZoom = 24;
70042         var kMin = geoZoomToScale(minZoom, TILESIZE);
70043         var kMax = geoZoomToScale(maxZoom, TILESIZE);
70044
70045         function clamp$1(num, min, max) {
70046           return Math.max(min, Math.min(num, max));
70047         }
70048
70049         function rendererMap(context) {
70050           var dispatch = dispatch$8('move', 'drawn', 'crossEditableZoom', 'hitMinZoom', 'changeHighlighting', 'changeAreaFill');
70051           var projection = context.projection;
70052           var curtainProjection = context.curtainProjection;
70053           var drawLayers;
70054           var drawPoints;
70055           var drawVertices;
70056           var drawLines;
70057           var drawAreas;
70058           var drawMidpoints;
70059           var drawLabels;
70060
70061           var _selection = select(null);
70062
70063           var supersurface = select(null);
70064           var wrapper = select(null);
70065           var surface = select(null);
70066           var _dimensions = [1, 1];
70067           var _dblClickZoomEnabled = true;
70068           var _redrawEnabled = true;
70069
70070           var _gestureTransformStart;
70071
70072           var _transformStart = projection.transform();
70073
70074           var _transformLast;
70075
70076           var _isTransformed = false;
70077           var _minzoom = 0;
70078
70079           var _getMouseCoords;
70080
70081           var _lastPointerEvent;
70082
70083           var _lastWithinEditableZoom; // whether a pointerdown event started the zoom
70084
70085
70086           var _pointerDown = false; // use pointer events on supported platforms; fallback to mouse events
70087
70088           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // use pointer event interaction if supported; fallback to touch/mouse events in d3-zoom
70089
70090
70091           var _zoomerPannerFunction = 'PointerEvent' in window ? utilZoomPan : d3_zoom;
70092
70093           var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(interpolate$1).filter(zoomEventFilter).on('zoom.map', zoomPan).on('start.map', function (d3_event) {
70094             _pointerDown = d3_event && (d3_event.type === 'pointerdown' || d3_event.sourceEvent && d3_event.sourceEvent.type === 'pointerdown');
70095           }).on('end.map', function () {
70096             _pointerDown = false;
70097           });
70098
70099           var _doubleUpHandler = utilDoubleUp();
70100
70101           var scheduleRedraw = throttle(redraw, 750); // var isRedrawScheduled = false;
70102           // var pendingRedrawCall;
70103           // function scheduleRedraw() {
70104           //     // Only schedule the redraw if one has not already been set.
70105           //     if (isRedrawScheduled) return;
70106           //     isRedrawScheduled = true;
70107           //     var that = this;
70108           //     var args = arguments;
70109           //     pendingRedrawCall = window.requestIdleCallback(function () {
70110           //         // Reset the boolean so future redraws can be set.
70111           //         isRedrawScheduled = false;
70112           //         redraw.apply(that, args);
70113           //     }, { timeout: 1400 });
70114           // }
70115
70116
70117           function cancelPendingRedraw() {
70118             scheduleRedraw.cancel(); // isRedrawScheduled = false;
70119             // window.cancelIdleCallback(pendingRedrawCall);
70120           }
70121
70122           function map(selection) {
70123             _selection = selection;
70124             context.on('change.map', immediateRedraw);
70125             var osm = context.connection();
70126
70127             if (osm) {
70128               osm.on('change.map', immediateRedraw);
70129             }
70130
70131             function didUndoOrRedo(targetTransform) {
70132               var mode = context.mode().id;
70133               if (mode !== 'browse' && mode !== 'select') return;
70134
70135               if (targetTransform) {
70136                 map.transformEase(targetTransform);
70137               }
70138             }
70139
70140             context.history().on('merge.map', function () {
70141               scheduleRedraw();
70142             }).on('change.map', immediateRedraw).on('undone.map', function (stack, fromStack) {
70143               didUndoOrRedo(fromStack.transform);
70144             }).on('redone.map', function (stack) {
70145               didUndoOrRedo(stack.transform);
70146             });
70147             context.background().on('change.map', immediateRedraw);
70148             context.features().on('redraw.map', immediateRedraw);
70149             drawLayers.on('change.map', function () {
70150               context.background().updateImagery();
70151               immediateRedraw();
70152             });
70153             selection.on('wheel.map mousewheel.map', function (d3_event) {
70154               // disable swipe-to-navigate browser pages on trackpad/magic mouse – #5552
70155               d3_event.preventDefault();
70156             }).call(_zoomerPanner).call(_zoomerPanner.transform, projection.transform()).on('dblclick.zoom', null); // override d3-zoom dblclick handling
70157
70158             map.supersurface = supersurface = selection.append('div').attr('class', 'supersurface').call(utilSetTransform, 0, 0); // Need a wrapper div because Opera can't cope with an absolutely positioned
70159             // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
70160
70161             wrapper = supersurface.append('div').attr('class', 'layer layer-data');
70162             map.surface = surface = wrapper.call(drawLayers).selectAll('.surface');
70163             surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + 'down.zoom', function (d3_event) {
70164               _lastPointerEvent = d3_event;
70165
70166               if (d3_event.button === 2) {
70167                 d3_event.stopPropagation();
70168               }
70169             }, true).on(_pointerPrefix + 'up.zoom', function (d3_event) {
70170               _lastPointerEvent = d3_event;
70171
70172               if (resetTransform()) {
70173                 immediateRedraw();
70174               }
70175             }).on(_pointerPrefix + 'move.map', function (d3_event) {
70176               _lastPointerEvent = d3_event;
70177             }).on(_pointerPrefix + 'over.vertices', function (d3_event) {
70178               if (map.editableDataEnabled() && !_isTransformed) {
70179                 var hover = d3_event.target.__data__;
70180                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
70181                 dispatch.call('drawn', this, {
70182                   full: false
70183                 });
70184               }
70185             }).on(_pointerPrefix + 'out.vertices', function (d3_event) {
70186               if (map.editableDataEnabled() && !_isTransformed) {
70187                 var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
70188                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
70189                 dispatch.call('drawn', this, {
70190                   full: false
70191                 });
70192               }
70193             });
70194             var detected = utilDetect(); // only WebKit supports gesture events
70195
70196             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
70197             // but we only need to do this on desktop Safari anyway. – #7694
70198             !detected.isMobileWebKit) {
70199               // Desktop Safari sends gesture events for multitouch trackpad pinches.
70200               // We can listen for these and translate them into map zooms.
70201               surface.on('gesturestart.surface', function (d3_event) {
70202                 d3_event.preventDefault();
70203                 _gestureTransformStart = projection.transform();
70204               }).on('gesturechange.surface', gestureChange);
70205             } // must call after surface init
70206
70207
70208             updateAreaFill();
70209
70210             _doubleUpHandler.on('doubleUp.map', function (d3_event, p0) {
70211               if (!_dblClickZoomEnabled) return; // don't zoom if targeting something other than the map itself
70212
70213               if (_typeof(d3_event.target.__data__) === 'object' && // or area fills
70214               !select(d3_event.target).classed('fill')) return;
70215               var zoomOut = d3_event.shiftKey;
70216               var t = projection.transform();
70217               var p1 = t.invert(p0);
70218               t = t.scale(zoomOut ? 0.5 : 2);
70219               t.x = p0[0] - p1[0] * t.k;
70220               t.y = p0[1] - p1[1] * t.k;
70221               map.transformEase(t);
70222             });
70223
70224             context.on('enter.map', function () {
70225               if (!map.editableDataEnabled(true
70226               /* skip zoom check */
70227               )) return; // redraw immediately any objects affected by a change in selectedIDs.
70228
70229               var graph = context.graph();
70230               var selectedAndParents = {};
70231               context.selectedIDs().forEach(function (id) {
70232                 var entity = graph.hasEntity(id);
70233
70234                 if (entity) {
70235                   selectedAndParents[entity.id] = entity;
70236
70237                   if (entity.type === 'node') {
70238                     graph.parentWays(entity).forEach(function (parent) {
70239                       selectedAndParents[parent.id] = parent;
70240                     });
70241                   }
70242                 }
70243               });
70244               var data = Object.values(selectedAndParents);
70245
70246               var filter = function filter(d) {
70247                 return d.id in selectedAndParents;
70248               };
70249
70250               data = context.features().filter(data, graph);
70251               surface.call(drawVertices.drawSelected, graph, map.extent()).call(drawLines, graph, data, filter).call(drawAreas, graph, data, filter).call(drawMidpoints, graph, data, filter, map.trimmedExtent());
70252               dispatch.call('drawn', this, {
70253                 full: false
70254               }); // redraw everything else later
70255
70256               scheduleRedraw();
70257             });
70258             map.dimensions(utilGetDimensions(selection));
70259           }
70260
70261           function zoomEventFilter(d3_event) {
70262             // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
70263             // Intercept `mousedown` and check if there is an orphaned zoom gesture.
70264             // This can happen if a previous `mousedown` occurred without a `mouseup`.
70265             // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
70266             // so that d3-zoom won't stop propagation of new `mousedown` events.
70267             if (d3_event.type === 'mousedown') {
70268               var hasOrphan = false;
70269               var listeners = window.__on;
70270
70271               for (var i = 0; i < listeners.length; i++) {
70272                 var listener = listeners[i];
70273
70274                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
70275                   hasOrphan = true;
70276                   break;
70277                 }
70278               }
70279
70280               if (hasOrphan) {
70281                 var event = window.CustomEvent;
70282
70283                 if (event) {
70284                   event = new event('mouseup');
70285                 } else {
70286                   event = window.document.createEvent('Event');
70287                   event.initEvent('mouseup', false, false);
70288                 } // Event needs to be dispatched with an event.view property.
70289
70290
70291                 event.view = window;
70292                 window.dispatchEvent(event);
70293               }
70294             }
70295
70296             return d3_event.button !== 2; // ignore right clicks
70297           }
70298
70299           function pxCenter() {
70300             return [_dimensions[0] / 2, _dimensions[1] / 2];
70301           }
70302
70303           function drawEditable(difference, extent) {
70304             var mode = context.mode();
70305             var graph = context.graph();
70306             var features = context.features();
70307             var all = context.history().intersects(map.extent());
70308             var fullRedraw = false;
70309             var data;
70310             var set;
70311             var filter;
70312             var applyFeatureLayerFilters = true;
70313
70314             if (map.isInWideSelection()) {
70315               data = [];
70316               utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function (id) {
70317                 var entity = context.hasEntity(id);
70318                 if (entity) data.push(entity);
70319               });
70320               fullRedraw = true;
70321               filter = utilFunctor(true); // selected features should always be visible, so we can skip filtering
70322
70323               applyFeatureLayerFilters = false;
70324             } else if (difference) {
70325               var complete = difference.complete(map.extent());
70326               data = Object.values(complete).filter(Boolean);
70327               set = new Set(Object.keys(complete));
70328
70329               filter = function filter(d) {
70330                 return set.has(d.id);
70331               };
70332
70333               features.clear(data);
70334             } else {
70335               // force a full redraw if gatherStats detects that a feature
70336               // should be auto-hidden (e.g. points or buildings)..
70337               if (features.gatherStats(all, graph, _dimensions)) {
70338                 extent = undefined;
70339               }
70340
70341               if (extent) {
70342                 data = context.history().intersects(map.extent().intersection(extent));
70343                 set = new Set(data.map(function (entity) {
70344                   return entity.id;
70345                 }));
70346
70347                 filter = function filter(d) {
70348                   return set.has(d.id);
70349                 };
70350               } else {
70351                 data = all;
70352                 fullRedraw = true;
70353                 filter = utilFunctor(true);
70354               }
70355             }
70356
70357             if (applyFeatureLayerFilters) {
70358               data = features.filter(data, graph);
70359             } else {
70360               context.features().resetStats();
70361             }
70362
70363             if (mode && mode.id === 'select') {
70364               // update selected vertices - the user might have just double-clicked a way,
70365               // creating a new vertex, triggering a partial redraw without a mode change
70366               surface.call(drawVertices.drawSelected, graph, map.extent());
70367             }
70368
70369             surface.call(drawVertices, graph, data, filter, map.extent(), fullRedraw).call(drawLines, graph, data, filter).call(drawAreas, graph, data, filter).call(drawMidpoints, graph, data, filter, map.trimmedExtent()).call(drawLabels, graph, data, filter, _dimensions, fullRedraw).call(drawPoints, graph, data, filter);
70370             dispatch.call('drawn', this, {
70371               full: true
70372             });
70373           }
70374
70375           map.init = function () {
70376             drawLayers = svgLayers(projection, context);
70377             drawPoints = svgPoints(projection, context);
70378             drawVertices = svgVertices(projection, context);
70379             drawLines = svgLines(projection, context);
70380             drawAreas = svgAreas(projection, context);
70381             drawMidpoints = svgMidpoints(projection, context);
70382             drawLabels = svgLabels(projection, context);
70383           };
70384
70385           function editOff() {
70386             context.features().resetStats();
70387             surface.selectAll('.layer-osm *').remove();
70388             surface.selectAll('.layer-touch:not(.markers) *').remove();
70389             var allowed = {
70390               'browse': true,
70391               'save': true,
70392               'select-note': true,
70393               'select-data': true,
70394               'select-error': true
70395             };
70396             var mode = context.mode();
70397
70398             if (mode && !allowed[mode.id]) {
70399               context.enter(modeBrowse(context));
70400             }
70401
70402             dispatch.call('drawn', this, {
70403               full: true
70404             });
70405           }
70406
70407           function gestureChange(d3_event) {
70408             // Remap Safari gesture events to wheel events - #5492
70409             // We want these disabled most places, but enabled for zoom/unzoom on map surface
70410             // https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
70411             var e = d3_event;
70412             e.preventDefault();
70413             var props = {
70414               deltaMode: 0,
70415               // dummy values to ignore in zoomPan
70416               deltaY: 1,
70417               // dummy values to ignore in zoomPan
70418               clientX: e.clientX,
70419               clientY: e.clientY,
70420               screenX: e.screenX,
70421               screenY: e.screenY,
70422               x: e.x,
70423               y: e.y
70424             };
70425             var e2 = new WheelEvent('wheel', props);
70426             e2._scale = e.scale; // preserve the original scale
70427
70428             e2._rotation = e.rotation; // preserve the original rotation
70429
70430             _selection.node().dispatchEvent(e2);
70431           }
70432
70433           function zoomPan(event, key, transform) {
70434             var source = event && event.sourceEvent || event;
70435             var eventTransform = transform || event && event.transform;
70436             var x = eventTransform.x;
70437             var y = eventTransform.y;
70438             var k = eventTransform.k; // Special handling of 'wheel' events:
70439             // They might be triggered by the user scrolling the mouse wheel,
70440             // or 2-finger pinch/zoom gestures, the transform may need adjustment.
70441
70442             if (source && source.type === 'wheel') {
70443               // assume that the gesture is already handled by pointer events
70444               if (_pointerDown) return;
70445               var detected = utilDetect();
70446               var dX = source.deltaX;
70447               var dY = source.deltaY;
70448               var x2 = x;
70449               var y2 = y;
70450               var k2 = k;
70451               var t0, p0, p1; // Normalize mousewheel scroll speed (Firefox) - #3029
70452               // If wheel delta is provided in LINE units, recalculate it in PIXEL units
70453               // We are essentially redoing the calculations that occur here:
70454               //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
70455               // See this for more info:
70456               //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
70457
70458               if (source.deltaMode === 1
70459               /* LINE */
70460               ) {
70461                   // Convert from lines to pixels, more if the user is scrolling fast.
70462                   // (I made up the exp function to roughly match Firefox to what Chrome does)
70463                   // These numbers should be floats, because integers are treated as pan gesture below.
70464                   var lines = Math.abs(source.deltaY);
70465                   var sign = source.deltaY > 0 ? 1 : -1;
70466                   dY = sign * clamp$1(Math.exp((lines - 1) * 0.75) * 4.000244140625, 4.000244140625, // min
70467                   350.000244140625 // max
70468                   ); // On Firefox Windows and Linux we always get +/- the scroll line amount (default 3)
70469                   // There doesn't seem to be any scroll acceleration.
70470                   // This multiplier increases the speed a little bit - #5512
70471
70472                   if (detected.os !== 'mac') {
70473                     dY *= 5;
70474                   } // recalculate x2,y2,k2
70475
70476
70477                   t0 = _isTransformed ? _transformLast : _transformStart;
70478                   p0 = _getMouseCoords(source);
70479                   p1 = t0.invert(p0);
70480                   k2 = t0.k * Math.pow(2, -dY / 500);
70481                   k2 = clamp$1(k2, kMin, kMax);
70482                   x2 = p0[0] - p1[0] * k2;
70483                   y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (Safari) - #5492
70484                   // These are fake `wheel` events we made from Safari `gesturechange` events..
70485                 } else if (source._scale) {
70486                 // recalculate x2,y2,k2
70487                 t0 = _gestureTransformStart;
70488                 p0 = _getMouseCoords(source);
70489                 p1 = t0.invert(p0);
70490                 k2 = t0.k * source._scale;
70491                 k2 = clamp$1(k2, kMin, kMax);
70492                 x2 = p0[0] - p1[0] * k2;
70493                 y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (all browsers except Safari) - #5492
70494                 // Pinch zooming via the `wheel` event will always have:
70495                 // - `ctrlKey = true`
70496                 // - `deltaY` is not round integer pixels (ignore `deltaX`)
70497               } else if (source.ctrlKey && !isInteger(dY)) {
70498                 dY *= 6; // slightly scale up whatever the browser gave us
70499                 // recalculate x2,y2,k2
70500
70501                 t0 = _isTransformed ? _transformLast : _transformStart;
70502                 p0 = _getMouseCoords(source);
70503                 p1 = t0.invert(p0);
70504                 k2 = t0.k * Math.pow(2, -dY / 500);
70505                 k2 = clamp$1(k2, kMin, kMax);
70506                 x2 = p0[0] - p1[0] * k2;
70507                 y2 = p0[1] - p1[1] * k2; // Trackpad scroll zooming with shift or alt/option key down
70508               } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
70509                 // recalculate x2,y2,k2
70510                 t0 = _isTransformed ? _transformLast : _transformStart;
70511                 p0 = _getMouseCoords(source);
70512                 p1 = t0.invert(p0);
70513                 k2 = t0.k * Math.pow(2, -dY / 500);
70514                 k2 = clamp$1(k2, kMin, kMax);
70515                 x2 = p0[0] - p1[0] * k2;
70516                 y2 = p0[1] - p1[1] * k2; // 2 finger map panning (Mac only, all browsers) - #5492, #5512
70517                 // Panning via the `wheel` event will always have:
70518                 // - `ctrlKey = false`
70519                 // - `deltaX`,`deltaY` are round integer pixels
70520               } else if (detected.os === 'mac' && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
70521                 p1 = projection.translate();
70522                 x2 = p1[0] - dX;
70523                 y2 = p1[1] - dY;
70524                 k2 = projection.scale();
70525                 k2 = clamp$1(k2, kMin, kMax);
70526               } // something changed - replace the event transform
70527
70528
70529               if (x2 !== x || y2 !== y || k2 !== k) {
70530                 x = x2;
70531                 y = y2;
70532                 k = k2;
70533                 eventTransform = identity$2.translate(x2, y2).scale(k2);
70534
70535                 if (_zoomerPanner._transform) {
70536                   // utilZoomPan interface
70537                   _zoomerPanner._transform(eventTransform);
70538                 } else {
70539                   // d3_zoom interface
70540                   _selection.node().__zoom = eventTransform;
70541                 }
70542               }
70543             }
70544
70545             if (_transformStart.x === x && _transformStart.y === y && _transformStart.k === k) {
70546               return; // no change
70547             }
70548
70549             if (geoScaleToZoom(k, TILESIZE) < _minzoom) {
70550               surface.interrupt();
70551               dispatch.call('hitMinZoom', this, map);
70552               setCenterZoom(map.center(), context.minEditableZoom(), 0, true);
70553               scheduleRedraw();
70554               dispatch.call('move', this, map);
70555               return;
70556             }
70557
70558             projection.transform(eventTransform);
70559             var withinEditableZoom = map.withinEditableZoom();
70560
70561             if (_lastWithinEditableZoom !== withinEditableZoom) {
70562               if (_lastWithinEditableZoom !== undefined) {
70563                 // notify that the map zoomed in or out over the editable zoom threshold
70564                 dispatch.call('crossEditableZoom', this, withinEditableZoom);
70565               }
70566
70567               _lastWithinEditableZoom = withinEditableZoom;
70568             }
70569
70570             var scale = k / _transformStart.k;
70571             var tX = (x / scale - _transformStart.x) * scale;
70572             var tY = (y / scale - _transformStart.y) * scale;
70573
70574             if (context.inIntro()) {
70575               curtainProjection.transform({
70576                 x: x - tX,
70577                 y: y - tY,
70578                 k: k
70579               });
70580             }
70581
70582             if (source) {
70583               _lastPointerEvent = event;
70584             }
70585
70586             _isTransformed = true;
70587             _transformLast = eventTransform;
70588             utilSetTransform(supersurface, tX, tY, scale);
70589             scheduleRedraw();
70590             dispatch.call('move', this, map);
70591
70592             function isInteger(val) {
70593               return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
70594             }
70595           }
70596
70597           function resetTransform() {
70598             if (!_isTransformed) return false;
70599             utilSetTransform(supersurface, 0, 0);
70600             _isTransformed = false;
70601
70602             if (context.inIntro()) {
70603               curtainProjection.transform(projection.transform());
70604             }
70605
70606             return true;
70607           }
70608
70609           function redraw(difference, extent) {
70610             if (surface.empty() || !_redrawEnabled) return; // If we are in the middle of a zoom/pan, we can't do differenced redraws.
70611             // It would result in artifacts where differenced entities are redrawn with
70612             // one transform and unchanged entities with another.
70613
70614             if (resetTransform()) {
70615               difference = extent = undefined;
70616             }
70617
70618             var zoom = map.zoom();
70619             var z = String(~~zoom);
70620
70621             if (surface.attr('data-zoom') !== z) {
70622               surface.attr('data-zoom', z);
70623             } // class surface as `lowzoom` around z17-z18.5 (based on latitude)
70624
70625
70626             var lat = map.center()[1];
70627             var lowzoom = linear().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
70628             surface.classed('low-zoom', zoom <= lowzoom(lat));
70629
70630             if (!difference) {
70631               supersurface.call(context.background());
70632               wrapper.call(drawLayers);
70633             } // OSM
70634
70635
70636             if (map.editableDataEnabled() || map.isInWideSelection()) {
70637               context.loadTiles(projection);
70638               drawEditable(difference, extent);
70639             } else {
70640               editOff();
70641             }
70642
70643             _transformStart = projection.transform();
70644             return map;
70645           }
70646
70647           var immediateRedraw = function immediateRedraw(difference, extent) {
70648             if (!difference && !extent) cancelPendingRedraw();
70649             redraw(difference, extent);
70650           };
70651
70652           map.lastPointerEvent = function () {
70653             return _lastPointerEvent;
70654           };
70655
70656           map.mouse = function (d3_event) {
70657             var event = d3_event || _lastPointerEvent;
70658
70659             if (event) {
70660               var s;
70661
70662               while (s = event.sourceEvent) {
70663                 event = s;
70664               }
70665
70666               return _getMouseCoords(event);
70667             }
70668
70669             return null;
70670           }; // returns Lng/Lat
70671
70672
70673           map.mouseCoordinates = function () {
70674             var coord = map.mouse() || pxCenter();
70675             return projection.invert(coord);
70676           };
70677
70678           map.dblclickZoomEnable = function (val) {
70679             if (!arguments.length) return _dblClickZoomEnabled;
70680             _dblClickZoomEnabled = val;
70681             return map;
70682           };
70683
70684           map.redrawEnable = function (val) {
70685             if (!arguments.length) return _redrawEnabled;
70686             _redrawEnabled = val;
70687             return map;
70688           };
70689
70690           map.isTransformed = function () {
70691             return _isTransformed;
70692           };
70693
70694           function setTransform(t2, duration, force) {
70695             var t = projection.transform();
70696             if (!force && t2.k === t.k && t2.x === t.x && t2.y === t.y) return false;
70697
70698             if (duration) {
70699               _selection.transition().duration(duration).on('start', function () {
70700                 map.startEase();
70701               }).call(_zoomerPanner.transform, identity$2.translate(t2.x, t2.y).scale(t2.k));
70702             } else {
70703               projection.transform(t2);
70704               _transformStart = t2;
70705
70706               _selection.call(_zoomerPanner.transform, _transformStart);
70707             }
70708
70709             return true;
70710           }
70711
70712           function setCenterZoom(loc2, z2, duration, force) {
70713             var c = map.center();
70714             var z = map.zoom();
70715             if (loc2[0] === c[0] && loc2[1] === c[1] && z2 === z && !force) return false;
70716             var proj = geoRawMercator().transform(projection.transform()); // copy projection
70717
70718             var k2 = clamp$1(geoZoomToScale(z2, TILESIZE), kMin, kMax);
70719             proj.scale(k2);
70720             var t = proj.translate();
70721             var point = proj(loc2);
70722             var center = pxCenter();
70723             t[0] += center[0] - point[0];
70724             t[1] += center[1] - point[1];
70725             return setTransform(identity$2.translate(t[0], t[1]).scale(k2), duration, force);
70726           }
70727
70728           map.pan = function (delta, duration) {
70729             var t = projection.translate();
70730             var k = projection.scale();
70731             t[0] += delta[0];
70732             t[1] += delta[1];
70733
70734             if (duration) {
70735               _selection.transition().duration(duration).on('start', function () {
70736                 map.startEase();
70737               }).call(_zoomerPanner.transform, identity$2.translate(t[0], t[1]).scale(k));
70738             } else {
70739               projection.translate(t);
70740               _transformStart = projection.transform();
70741
70742               _selection.call(_zoomerPanner.transform, _transformStart);
70743
70744               dispatch.call('move', this, map);
70745               immediateRedraw();
70746             }
70747
70748             return map;
70749           };
70750
70751           map.dimensions = function (val) {
70752             if (!arguments.length) return _dimensions;
70753             _dimensions = val;
70754             drawLayers.dimensions(_dimensions);
70755             context.background().dimensions(_dimensions);
70756             projection.clipExtent([[0, 0], _dimensions]);
70757             _getMouseCoords = utilFastMouse(supersurface.node());
70758             scheduleRedraw();
70759             return map;
70760           };
70761
70762           function zoomIn(delta) {
70763             setCenterZoom(map.center(), ~~map.zoom() + delta, 250, true);
70764           }
70765
70766           function zoomOut(delta) {
70767             setCenterZoom(map.center(), ~~map.zoom() - delta, 250, true);
70768           }
70769
70770           map.zoomIn = function () {
70771             zoomIn(1);
70772           };
70773
70774           map.zoomInFurther = function () {
70775             zoomIn(4);
70776           };
70777
70778           map.canZoomIn = function () {
70779             return map.zoom() < maxZoom;
70780           };
70781
70782           map.zoomOut = function () {
70783             zoomOut(1);
70784           };
70785
70786           map.zoomOutFurther = function () {
70787             zoomOut(4);
70788           };
70789
70790           map.canZoomOut = function () {
70791             return map.zoom() > minZoom;
70792           };
70793
70794           map.center = function (loc2) {
70795             if (!arguments.length) {
70796               return projection.invert(pxCenter());
70797             }
70798
70799             if (setCenterZoom(loc2, map.zoom())) {
70800               dispatch.call('move', this, map);
70801             }
70802
70803             scheduleRedraw();
70804             return map;
70805           };
70806
70807           map.unobscuredCenterZoomEase = function (loc, zoom) {
70808             var offset = map.unobscuredOffsetPx();
70809             var proj = geoRawMercator().transform(projection.transform()); // copy projection
70810             // use the target zoom to calculate the offset center
70811
70812             proj.scale(geoZoomToScale(zoom, TILESIZE));
70813             var locPx = proj(loc);
70814             var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
70815             var offsetLoc = proj.invert(offsetLocPx);
70816             map.centerZoomEase(offsetLoc, zoom);
70817           };
70818
70819           map.unobscuredOffsetPx = function () {
70820             var openPane = context.container().select('.map-panes .map-pane.shown');
70821
70822             if (!openPane.empty()) {
70823               return [openPane.node().offsetWidth / 2, 0];
70824             }
70825
70826             return [0, 0];
70827           };
70828
70829           map.zoom = function (z2) {
70830             if (!arguments.length) {
70831               return Math.max(geoScaleToZoom(projection.scale(), TILESIZE), 0);
70832             }
70833
70834             if (z2 < _minzoom) {
70835               surface.interrupt();
70836               dispatch.call('hitMinZoom', this, map);
70837               z2 = context.minEditableZoom();
70838             }
70839
70840             if (setCenterZoom(map.center(), z2)) {
70841               dispatch.call('move', this, map);
70842             }
70843
70844             scheduleRedraw();
70845             return map;
70846           };
70847
70848           map.centerZoom = function (loc2, z2) {
70849             if (setCenterZoom(loc2, z2)) {
70850               dispatch.call('move', this, map);
70851             }
70852
70853             scheduleRedraw();
70854             return map;
70855           };
70856
70857           map.zoomTo = function (entity) {
70858             var extent = entity.extent(context.graph());
70859             if (!isFinite(extent.area())) return map;
70860             var z2 = clamp$1(map.trimmedExtentZoom(extent), 0, 20);
70861             return map.centerZoom(extent.center(), z2);
70862           };
70863
70864           map.centerEase = function (loc2, duration) {
70865             duration = duration || 250;
70866             setCenterZoom(loc2, map.zoom(), duration);
70867             return map;
70868           };
70869
70870           map.zoomEase = function (z2, duration) {
70871             duration = duration || 250;
70872             setCenterZoom(map.center(), z2, duration, false);
70873             return map;
70874           };
70875
70876           map.centerZoomEase = function (loc2, z2, duration) {
70877             duration = duration || 250;
70878             setCenterZoom(loc2, z2, duration, false);
70879             return map;
70880           };
70881
70882           map.transformEase = function (t2, duration) {
70883             duration = duration || 250;
70884             setTransform(t2, duration, false
70885             /* don't force */
70886             );
70887             return map;
70888           };
70889
70890           map.zoomToEase = function (obj, duration) {
70891             var extent;
70892
70893             if (Array.isArray(obj)) {
70894               obj.forEach(function (entity) {
70895                 var entityExtent = entity.extent(context.graph());
70896
70897                 if (!extent) {
70898                   extent = entityExtent;
70899                 } else {
70900                   extent = extent.extend(entityExtent);
70901                 }
70902               });
70903             } else {
70904               extent = obj.extent(context.graph());
70905             }
70906
70907             if (!isFinite(extent.area())) return map;
70908             var z2 = clamp$1(map.trimmedExtentZoom(extent), 0, 20);
70909             return map.centerZoomEase(extent.center(), z2, duration);
70910           };
70911
70912           map.startEase = function () {
70913             utilBindOnce(surface, _pointerPrefix + 'down.ease', function () {
70914               map.cancelEase();
70915             });
70916             return map;
70917           };
70918
70919           map.cancelEase = function () {
70920             _selection.interrupt();
70921
70922             return map;
70923           };
70924
70925           map.extent = function (val) {
70926             if (!arguments.length) {
70927               return new geoExtent(projection.invert([0, _dimensions[1]]), projection.invert([_dimensions[0], 0]));
70928             } else {
70929               var extent = geoExtent(val);
70930               map.centerZoom(extent.center(), map.extentZoom(extent));
70931             }
70932           };
70933
70934           map.trimmedExtent = function (val) {
70935             if (!arguments.length) {
70936               var headerY = 71;
70937               var footerY = 30;
70938               var pad = 10;
70939               return new geoExtent(projection.invert([pad, _dimensions[1] - footerY - pad]), projection.invert([_dimensions[0] - pad, headerY + pad]));
70940             } else {
70941               var extent = geoExtent(val);
70942               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
70943             }
70944           };
70945
70946           function calcExtentZoom(extent, dim) {
70947             var tl = projection([extent[0][0], extent[1][1]]);
70948             var br = projection([extent[1][0], extent[0][1]]); // Calculate maximum zoom that fits extent
70949
70950             var hFactor = (br[0] - tl[0]) / dim[0];
70951             var vFactor = (br[1] - tl[1]) / dim[1];
70952             var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
70953             var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
70954             var newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
70955             return newZoom;
70956           }
70957
70958           map.extentZoom = function (val) {
70959             return calcExtentZoom(geoExtent(val), _dimensions);
70960           };
70961
70962           map.trimmedExtentZoom = function (val) {
70963             var trimY = 120;
70964             var trimX = 40;
70965             var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
70966             return calcExtentZoom(geoExtent(val), trimmed);
70967           };
70968
70969           map.withinEditableZoom = function () {
70970             return map.zoom() >= context.minEditableZoom();
70971           };
70972
70973           map.isInWideSelection = function () {
70974             return !map.withinEditableZoom() && context.selectedIDs().length;
70975           };
70976
70977           map.editableDataEnabled = function (skipZoomCheck) {
70978             var layer = context.layers().layer('osm');
70979             if (!layer || !layer.enabled()) return false;
70980             return skipZoomCheck || map.withinEditableZoom();
70981           };
70982
70983           map.notesEditable = function () {
70984             var layer = context.layers().layer('notes');
70985             if (!layer || !layer.enabled()) return false;
70986             return map.withinEditableZoom();
70987           };
70988
70989           map.minzoom = function (val) {
70990             if (!arguments.length) return _minzoom;
70991             _minzoom = val;
70992             return map;
70993           };
70994
70995           map.toggleHighlightEdited = function () {
70996             surface.classed('highlight-edited', !surface.classed('highlight-edited'));
70997             map.pan([0, 0]); // trigger a redraw
70998
70999             dispatch.call('changeHighlighting', this);
71000           };
71001
71002           map.areaFillOptions = ['wireframe', 'partial', 'full'];
71003
71004           map.activeAreaFill = function (val) {
71005             if (!arguments.length) return corePreferences('area-fill') || 'partial';
71006             corePreferences('area-fill', val);
71007
71008             if (val !== 'wireframe') {
71009               corePreferences('area-fill-toggle', val);
71010             }
71011
71012             updateAreaFill();
71013             map.pan([0, 0]); // trigger a redraw
71014
71015             dispatch.call('changeAreaFill', this);
71016             return map;
71017           };
71018
71019           map.toggleWireframe = function () {
71020             var activeFill = map.activeAreaFill();
71021
71022             if (activeFill === 'wireframe') {
71023               activeFill = corePreferences('area-fill-toggle') || 'partial';
71024             } else {
71025               activeFill = 'wireframe';
71026             }
71027
71028             map.activeAreaFill(activeFill);
71029           };
71030
71031           function updateAreaFill() {
71032             var activeFill = map.activeAreaFill();
71033             map.areaFillOptions.forEach(function (opt) {
71034               surface.classed('fill-' + opt, Boolean(opt === activeFill));
71035             });
71036           }
71037
71038           map.layers = function () {
71039             return drawLayers;
71040           };
71041
71042           map.doubleUpHandler = function () {
71043             return _doubleUpHandler;
71044           };
71045
71046           return utilRebind(map, dispatch, 'on');
71047         }
71048
71049         function rendererPhotos(context) {
71050           var dispatch = dispatch$8('change');
71051           var _layerIDs = ['streetside', 'mapillary', 'mapillary-map-features', 'mapillary-signs', 'openstreetcam'];
71052           var _allPhotoTypes = ['flat', 'panoramic'];
71053
71054           var _shownPhotoTypes = _allPhotoTypes.slice(); // shallow copy
71055
71056
71057           var _dateFilters = ['fromDate', 'toDate'];
71058
71059           var _fromDate;
71060
71061           var _toDate;
71062
71063           var _usernames;
71064
71065           function photos() {}
71066
71067           function updateStorage() {
71068             if (window.mocha) return;
71069             var hash = utilStringQs(window.location.hash);
71070             var enabled = context.layers().all().filter(function (d) {
71071               return _layerIDs.indexOf(d.id) !== -1 && d.layer && d.layer.supported() && d.layer.enabled();
71072             }).map(function (d) {
71073               return d.id;
71074             });
71075
71076             if (enabled.length) {
71077               hash.photo_overlay = enabled.join(',');
71078             } else {
71079               delete hash.photo_overlay;
71080             }
71081
71082             window.location.replace('#' + utilQsString(hash, true));
71083           }
71084
71085           photos.overlayLayerIDs = function () {
71086             return _layerIDs;
71087           };
71088
71089           photos.allPhotoTypes = function () {
71090             return _allPhotoTypes;
71091           };
71092
71093           photos.dateFilters = function () {
71094             return _dateFilters;
71095           };
71096
71097           photos.dateFilterValue = function (val) {
71098             return val === _dateFilters[0] ? _fromDate : _toDate;
71099           };
71100
71101           photos.setDateFilter = function (type, val, updateUrl) {
71102             // validate the date
71103             var date = val && new Date(val);
71104
71105             if (date && !isNaN(date)) {
71106               val = date.toISOString().substr(0, 10);
71107             } else {
71108               val = null;
71109             }
71110
71111             if (type === _dateFilters[0]) {
71112               _fromDate = val;
71113
71114               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
71115                 _toDate = _fromDate;
71116               }
71117             }
71118
71119             if (type === _dateFilters[1]) {
71120               _toDate = val;
71121
71122               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
71123                 _fromDate = _toDate;
71124               }
71125             }
71126
71127             dispatch.call('change', this);
71128
71129             if (updateUrl) {
71130               var rangeString;
71131
71132               if (_fromDate || _toDate) {
71133                 rangeString = (_fromDate || '') + '_' + (_toDate || '');
71134               }
71135
71136               setUrlFilterValue('photo_dates', rangeString);
71137             }
71138           };
71139
71140           photos.setUsernameFilter = function (val, updateUrl) {
71141             if (val && typeof val === 'string') val = val.replace(/;/g, ',').split(',');
71142
71143             if (val) {
71144               val = val.map(function (d) {
71145                 return d.trim();
71146               }).filter(Boolean);
71147
71148               if (!val.length) {
71149                 val = null;
71150               }
71151             }
71152
71153             _usernames = val;
71154             dispatch.call('change', this);
71155
71156             if (updateUrl) {
71157               var hashString;
71158
71159               if (_usernames) {
71160                 hashString = _usernames.join(',');
71161               }
71162
71163               setUrlFilterValue('photo_username', hashString);
71164             }
71165           };
71166
71167           function setUrlFilterValue(property, val) {
71168             if (!window.mocha) {
71169               var hash = utilStringQs(window.location.hash);
71170
71171               if (val) {
71172                 if (hash[property] === val) return;
71173                 hash[property] = val;
71174               } else {
71175                 if (!(property in hash)) return;
71176                 delete hash[property];
71177               }
71178
71179               window.location.replace('#' + utilQsString(hash, true));
71180             }
71181           }
71182
71183           function showsLayer(id) {
71184             var layer = context.layers().layer(id);
71185             return layer && layer.supported() && layer.enabled();
71186           }
71187
71188           photos.shouldFilterByDate = function () {
71189             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
71190           };
71191
71192           photos.shouldFilterByPhotoType = function () {
71193             return showsLayer('mapillary') || showsLayer('streetside') && showsLayer('openstreetcam');
71194           };
71195
71196           photos.shouldFilterByUsername = function () {
71197             return !showsLayer('mapillary') && showsLayer('openstreetcam') && !showsLayer('streetside');
71198           };
71199
71200           photos.showsPhotoType = function (val) {
71201             if (!photos.shouldFilterByPhotoType()) return true;
71202             return _shownPhotoTypes.indexOf(val) !== -1;
71203           };
71204
71205           photos.showsFlat = function () {
71206             return photos.showsPhotoType('flat');
71207           };
71208
71209           photos.showsPanoramic = function () {
71210             return photos.showsPhotoType('panoramic');
71211           };
71212
71213           photos.fromDate = function () {
71214             return _fromDate;
71215           };
71216
71217           photos.toDate = function () {
71218             return _toDate;
71219           };
71220
71221           photos.togglePhotoType = function (val) {
71222             var index = _shownPhotoTypes.indexOf(val);
71223
71224             if (index !== -1) {
71225               _shownPhotoTypes.splice(index, 1);
71226             } else {
71227               _shownPhotoTypes.push(val);
71228             }
71229
71230             dispatch.call('change', this);
71231             return photos;
71232           };
71233
71234           photos.usernames = function () {
71235             return _usernames;
71236           };
71237
71238           photos.init = function () {
71239             var hash = utilStringQs(window.location.hash);
71240
71241             if (hash.photo_dates) {
71242               // expect format like `photo_dates=2019-01-01_2020-12-31`, but allow a couple different separators
71243               var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
71244               this.setDateFilter('fromDate', parts && parts.length >= 2 && parts[1], false);
71245               this.setDateFilter('toDate', parts && parts.length >= 3 && parts[2], false);
71246             }
71247
71248             if (hash.photo_username) {
71249               this.setUsernameFilter(hash.photo_username, false);
71250             }
71251
71252             if (hash.photo_overlay) {
71253               // support enabling photo layers by default via a URL parameter, e.g. `photo_overlay=openstreetcam;mapillary;streetside`
71254               var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ',').split(',');
71255               hashOverlayIDs.forEach(function (id) {
71256                 var layer = _layerIDs.indexOf(id) !== -1 && context.layers().layer(id);
71257                 if (layer && !layer.enabled()) layer.enabled(true);
71258               });
71259             }
71260
71261             if (hash.photo) {
71262               // support opening a photo via a URL parameter, e.g. `photo=mapillary-fztgSDtLpa08ohPZFZjeRQ`
71263               var photoIds = hash.photo.replace(/;/g, ',').split(',');
71264               var photoId = photoIds.length && photoIds[0].trim();
71265               var results = /(.*)\/(.*)/g.exec(photoId);
71266
71267               if (results && results.length >= 3) {
71268                 var serviceId = results[1];
71269                 var photoKey = results[2];
71270                 var service = services[serviceId];
71271
71272                 if (service && service.ensureViewerLoaded) {
71273                   // if we're showing a photo then make sure its layer is enabled too
71274                   var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
71275                   if (layer && !layer.enabled()) layer.enabled(true);
71276                   var baselineTime = Date.now();
71277                   service.on('loadedImages.rendererPhotos', function () {
71278                     // don't open the viewer if too much time has elapsed
71279                     if (Date.now() - baselineTime > 45000) {
71280                       service.on('loadedImages.rendererPhotos', null);
71281                       return;
71282                     }
71283
71284                     if (!service.cachedImage(photoKey)) return;
71285                     service.on('loadedImages.rendererPhotos', null);
71286                     service.ensureViewerLoaded(context).then(function () {
71287                       service.selectImage(context, photoKey).showViewer(context);
71288                     });
71289                   });
71290                 }
71291               }
71292             }
71293
71294             context.layers().on('change.rendererPhotos', updateStorage);
71295           };
71296
71297           return utilRebind(photos, dispatch, 'on');
71298         }
71299
71300         function uiAccount(context) {
71301           var osm = context.connection();
71302
71303           function update(selection) {
71304             if (!osm) return;
71305
71306             if (!osm.authenticated()) {
71307               selection.selectAll('.userLink, .logoutLink').classed('hide', true);
71308               return;
71309             }
71310
71311             osm.userDetails(function (err, details) {
71312               var userLink = selection.select('.userLink'),
71313                   logoutLink = selection.select('.logoutLink');
71314               userLink.html('');
71315               logoutLink.html('');
71316               if (err || !details) return;
71317               selection.selectAll('.userLink, .logoutLink').classed('hide', false); // Link
71318
71319               var userLinkA = userLink.append('a').attr('href', osm.userURL(details.display_name)).attr('target', '_blank'); // Add thumbnail or dont
71320
71321               if (details.image_url) {
71322                 userLinkA.append('img').attr('class', 'icon pre-text user-icon').attr('src', details.image_url);
71323               } else {
71324                 userLinkA.call(svgIcon('#iD-icon-avatar', 'pre-text light'));
71325               } // Add user name
71326
71327
71328               userLinkA.append('span').attr('class', 'label').html(details.display_name);
71329               logoutLink.append('a').attr('class', 'logout').attr('href', '#').html(_t.html('logout')).on('click.logout', function (d3_event) {
71330                 d3_event.preventDefault();
71331                 osm.logout();
71332               });
71333             });
71334           }
71335
71336           return function (selection) {
71337             selection.append('li').attr('class', 'userLink').classed('hide', true);
71338             selection.append('li').attr('class', 'logoutLink').classed('hide', true);
71339
71340             if (osm) {
71341               osm.on('change.account', function () {
71342                 update(selection);
71343               });
71344               update(selection);
71345             }
71346           };
71347         }
71348
71349         function uiAttribution(context) {
71350           var _selection = select(null);
71351
71352           function render(selection, data, klass) {
71353             var div = selection.selectAll(".".concat(klass)).data([0]);
71354             div = div.enter().append('div').attr('class', klass).merge(div);
71355             var attributions = div.selectAll('.attribution').data(data, function (d) {
71356               return d.id;
71357             });
71358             attributions.exit().remove();
71359             attributions = attributions.enter().append('span').attr('class', 'attribution').each(function (d, i, nodes) {
71360               var attribution = select(nodes[i]);
71361
71362               if (d.terms_html) {
71363                 attribution.html(d.terms_html);
71364                 return;
71365               }
71366
71367               if (d.terms_url) {
71368                 attribution = attribution.append('a').attr('href', d.terms_url).attr('target', '_blank');
71369               }
71370
71371               var sourceID = d.id.replace(/\./g, '<TX_DOT>');
71372               var terms_text = _t("imagery.".concat(sourceID, ".attribution.text"), {
71373                 "default": d.terms_text || d.id || d.name()
71374               });
71375
71376               if (d.icon && !d.overlay) {
71377                 attribution.append('img').attr('class', 'source-image').attr('src', d.icon);
71378               }
71379
71380               attribution.append('span').attr('class', 'attribution-text').html(terms_text);
71381             }).merge(attributions);
71382             var copyright = attributions.selectAll('.copyright-notice').data(function (d) {
71383               var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
71384               return notice ? [notice] : [];
71385             });
71386             copyright.exit().remove();
71387             copyright = copyright.enter().append('span').attr('class', 'copyright-notice').merge(copyright);
71388             copyright.html(String);
71389           }
71390
71391           function update() {
71392             var baselayer = context.background().baseLayerSource();
71393
71394             _selection.call(render, baselayer ? [baselayer] : [], 'base-layer-attribution');
71395
71396             var z = context.map().zoom();
71397             var overlays = context.background().overlayLayerSources() || [];
71398
71399             _selection.call(render, overlays.filter(function (s) {
71400               return s.validZoom(z);
71401             }), 'overlay-layer-attribution');
71402           }
71403
71404           return function (selection) {
71405             _selection = selection;
71406             context.background().on('change.attribution', update);
71407             context.map().on('move.attribution', throttle(update, 400, {
71408               leading: false
71409             }));
71410             update();
71411           };
71412         }
71413
71414         function uiContributors(context) {
71415           var osm = context.connection(),
71416               debouncedUpdate = debounce(function () {
71417             update();
71418           }, 1000),
71419               limit = 4,
71420               hidden = false,
71421               wrap = select(null);
71422
71423           function update() {
71424             if (!osm) return;
71425             var users = {},
71426                 entities = context.history().intersects(context.map().extent());
71427             entities.forEach(function (entity) {
71428               if (entity && entity.user) users[entity.user] = true;
71429             });
71430             var u = Object.keys(users),
71431                 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
71432             wrap.html('').call(svgIcon('#iD-icon-nearby', 'pre-text light'));
71433             var userList = select(document.createElement('span'));
71434             userList.selectAll().data(subset).enter().append('a').attr('class', 'user-link').attr('href', function (d) {
71435               return osm.userURL(d);
71436             }).attr('target', '_blank').html(String);
71437
71438             if (u.length > limit) {
71439               var count = select(document.createElement('span'));
71440               var othersNum = u.length - limit + 1;
71441               count.append('a').attr('target', '_blank').attr('href', function () {
71442                 return osm.changesetsURL(context.map().center(), context.map().zoom());
71443               }).html(othersNum);
71444               wrap.append('span').html(_t.html('contributors.truncated_list', {
71445                 n: othersNum,
71446                 users: userList.html(),
71447                 count: count.html()
71448               }));
71449             } else {
71450               wrap.append('span').html(_t.html('contributors.list', {
71451                 users: userList.html()
71452               }));
71453             }
71454
71455             if (!u.length) {
71456               hidden = true;
71457               wrap.transition().style('opacity', 0);
71458             } else if (hidden) {
71459               wrap.transition().style('opacity', 1);
71460             }
71461           }
71462
71463           return function (selection) {
71464             if (!osm) return;
71465             wrap = selection;
71466             update();
71467             osm.on('loaded.contributors', debouncedUpdate);
71468             context.map().on('move.contributors', debouncedUpdate);
71469           };
71470         }
71471
71472         var _popoverID = 0;
71473         function uiPopover(klass) {
71474           var _id = _popoverID++;
71475
71476           var _anchorSelection = select(null);
71477
71478           var popover = function popover(selection) {
71479             _anchorSelection = selection;
71480             selection.each(setup);
71481           };
71482
71483           var _animation = utilFunctor(false);
71484
71485           var _placement = utilFunctor('top'); // top, bottom, left, right
71486
71487
71488           var _alignment = utilFunctor('center'); // leading, center, trailing
71489
71490
71491           var _scrollContainer = utilFunctor(select(null));
71492
71493           var _content;
71494
71495           var _displayType = utilFunctor('');
71496
71497           var _hasArrow = utilFunctor(true); // use pointer events on supported platforms; fallback to mouse events
71498
71499
71500           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
71501
71502           popover.displayType = function (val) {
71503             if (arguments.length) {
71504               _displayType = utilFunctor(val);
71505               return popover;
71506             } else {
71507               return _displayType;
71508             }
71509           };
71510
71511           popover.hasArrow = function (val) {
71512             if (arguments.length) {
71513               _hasArrow = utilFunctor(val);
71514               return popover;
71515             } else {
71516               return _hasArrow;
71517             }
71518           };
71519
71520           popover.placement = function (val) {
71521             if (arguments.length) {
71522               _placement = utilFunctor(val);
71523               return popover;
71524             } else {
71525               return _placement;
71526             }
71527           };
71528
71529           popover.alignment = function (val) {
71530             if (arguments.length) {
71531               _alignment = utilFunctor(val);
71532               return popover;
71533             } else {
71534               return _alignment;
71535             }
71536           };
71537
71538           popover.scrollContainer = function (val) {
71539             if (arguments.length) {
71540               _scrollContainer = utilFunctor(val);
71541               return popover;
71542             } else {
71543               return _scrollContainer;
71544             }
71545           };
71546
71547           popover.content = function (val) {
71548             if (arguments.length) {
71549               _content = val;
71550               return popover;
71551             } else {
71552               return _content;
71553             }
71554           };
71555
71556           popover.isShown = function () {
71557             var popoverSelection = _anchorSelection.select('.popover-' + _id);
71558
71559             return !popoverSelection.empty() && popoverSelection.classed('in');
71560           };
71561
71562           popover.show = function () {
71563             _anchorSelection.each(show);
71564           };
71565
71566           popover.updateContent = function () {
71567             _anchorSelection.each(updateContent);
71568           };
71569
71570           popover.hide = function () {
71571             _anchorSelection.each(hide);
71572           };
71573
71574           popover.toggle = function () {
71575             _anchorSelection.each(toggle);
71576           };
71577
71578           popover.destroy = function (selection, selector) {
71579             // by default, just destroy the current popover
71580             selector = selector || '.popover-' + _id;
71581             selection.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 () {
71582               return this.getAttribute('data-original-title') || this.getAttribute('title');
71583             }).attr('data-original-title', null).selectAll(selector).remove();
71584           };
71585
71586           popover.destroyAny = function (selection) {
71587             selection.call(popover.destroy, '.popover');
71588           };
71589
71590           function setup() {
71591             var anchor = select(this);
71592
71593             var animate = _animation.apply(this, arguments);
71594
71595             var popoverSelection = anchor.selectAll('.popover-' + _id).data([0]);
71596             var enter = popoverSelection.enter().append('div').attr('class', 'popover popover-' + _id + ' ' + (klass ? klass : '')).classed('arrowed', _hasArrow.apply(this, arguments));
71597             enter.append('div').attr('class', 'popover-arrow');
71598             enter.append('div').attr('class', 'popover-inner');
71599             popoverSelection = enter.merge(popoverSelection);
71600
71601             if (animate) {
71602               popoverSelection.classed('fade', true);
71603             }
71604
71605             var display = _displayType.apply(this, arguments);
71606
71607             if (display === 'hover') {
71608               var _lastNonMouseEnterTime;
71609
71610               anchor.on(_pointerPrefix + 'enter.popover', function (d3_event) {
71611                 if (d3_event.pointerType) {
71612                   if (d3_event.pointerType !== 'mouse') {
71613                     _lastNonMouseEnterTime = d3_event.timeStamp; // only allow hover behavior for mouse input
71614
71615                     return;
71616                   } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
71617                     // HACK: iOS 13.4 sends an erroneous `mouse` type pointerenter
71618                     // event for non-mouse interactions right after sending
71619                     // the correct type pointerenter event. Workaround by discarding
71620                     // any mouse event that occurs immediately after a non-mouse event.
71621                     return;
71622                   }
71623                 } // don't show if buttons are pressed, e.g. during click and drag of map
71624
71625
71626                 if (d3_event.buttons !== 0) return;
71627                 show.apply(this, arguments);
71628               }).on(_pointerPrefix + 'leave.popover', function () {
71629                 hide.apply(this, arguments);
71630               }) // show on focus too for better keyboard navigation support
71631               .on('focus.popover', function () {
71632                 show.apply(this, arguments);
71633               }).on('blur.popover', function () {
71634                 hide.apply(this, arguments);
71635               });
71636             } else if (display === 'clickFocus') {
71637               anchor.on(_pointerPrefix + 'down.popover', function (d3_event) {
71638                 d3_event.preventDefault();
71639                 d3_event.stopPropagation();
71640               }).on(_pointerPrefix + 'up.popover', function (d3_event) {
71641                 d3_event.preventDefault();
71642                 d3_event.stopPropagation();
71643               }).on('click.popover', toggle);
71644               popoverSelection // This attribute lets the popover take focus
71645               .attr('tabindex', 0).on('blur.popover', function () {
71646                 anchor.each(function () {
71647                   hide.apply(this, arguments);
71648                 });
71649               });
71650             }
71651           }
71652
71653           function show() {
71654             var anchor = select(this);
71655             var popoverSelection = anchor.selectAll('.popover-' + _id);
71656
71657             if (popoverSelection.empty()) {
71658               // popover was removed somehow, put it back
71659               anchor.call(popover.destroy);
71660               anchor.each(setup);
71661               popoverSelection = anchor.selectAll('.popover-' + _id);
71662             }
71663
71664             popoverSelection.classed('in', true);
71665
71666             var displayType = _displayType.apply(this, arguments);
71667
71668             if (displayType === 'clickFocus') {
71669               anchor.classed('active', true);
71670               popoverSelection.node().focus();
71671             }
71672
71673             anchor.each(updateContent);
71674           }
71675
71676           function updateContent() {
71677             var anchor = select(this);
71678
71679             if (_content) {
71680               anchor.selectAll('.popover-' + _id + ' > .popover-inner').call(_content.apply(this, arguments));
71681             }
71682
71683             updatePosition.apply(this, arguments); // hack: update multiple times to fix instances where the absolute offset is
71684             // set before the dynamic popover size is calculated by the browser
71685
71686             updatePosition.apply(this, arguments);
71687             updatePosition.apply(this, arguments);
71688           }
71689
71690           function updatePosition() {
71691             var anchor = select(this);
71692             var popoverSelection = anchor.selectAll('.popover-' + _id);
71693
71694             var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
71695
71696             var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
71697             var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
71698             var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
71699
71700             var placement = _placement.apply(this, arguments);
71701
71702             popoverSelection.classed('left', false).classed('right', false).classed('top', false).classed('bottom', false).classed(placement, true);
71703
71704             var alignment = _alignment.apply(this, arguments);
71705
71706             var alignFactor = 0.5;
71707
71708             if (alignment === 'leading') {
71709               alignFactor = 0;
71710             } else if (alignment === 'trailing') {
71711               alignFactor = 1;
71712             }
71713
71714             var anchorFrame = getFrame(anchor.node());
71715             var popoverFrame = getFrame(popoverSelection.node());
71716             var position;
71717
71718             switch (placement) {
71719               case 'top':
71720                 position = {
71721                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
71722                   y: anchorFrame.y - popoverFrame.h
71723                 };
71724                 break;
71725
71726               case 'bottom':
71727                 position = {
71728                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
71729                   y: anchorFrame.y + anchorFrame.h
71730                 };
71731                 break;
71732
71733               case 'left':
71734                 position = {
71735                   x: anchorFrame.x - popoverFrame.w,
71736                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
71737                 };
71738                 break;
71739
71740               case 'right':
71741                 position = {
71742                   x: anchorFrame.x + anchorFrame.w,
71743                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
71744                 };
71745                 break;
71746             }
71747
71748             if (position) {
71749               if (scrollNode && (placement === 'top' || placement === 'bottom')) {
71750                 var initialPosX = position.x;
71751
71752                 if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
71753                   position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
71754                 } else if (position.x < 10) {
71755                   position.x = 10;
71756                 }
71757
71758                 var arrow = anchor.selectAll('.popover-' + _id + ' > .popover-arrow'); // keep the arrow centered on the button, or as close as possible
71759
71760                 var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
71761                 arrow.style('left', ~~arrowPosX + 'px');
71762               }
71763
71764               popoverSelection.style('left', ~~position.x + 'px').style('top', ~~position.y + 'px');
71765             } else {
71766               popoverSelection.style('left', null).style('top', null);
71767             }
71768
71769             function getFrame(node) {
71770               var positionStyle = select(node).style('position');
71771
71772               if (positionStyle === 'absolute' || positionStyle === 'static') {
71773                 return {
71774                   x: node.offsetLeft - scrollLeft,
71775                   y: node.offsetTop - scrollTop,
71776                   w: node.offsetWidth,
71777                   h: node.offsetHeight
71778                 };
71779               } else {
71780                 return {
71781                   x: 0,
71782                   y: 0,
71783                   w: node.offsetWidth,
71784                   h: node.offsetHeight
71785                 };
71786               }
71787             }
71788           }
71789
71790           function hide() {
71791             var anchor = select(this);
71792
71793             if (_displayType.apply(this, arguments) === 'clickFocus') {
71794               anchor.classed('active', false);
71795             }
71796
71797             anchor.selectAll('.popover-' + _id).classed('in', false);
71798           }
71799
71800           function toggle() {
71801             if (select(this).select('.popover-' + _id).classed('in')) {
71802               hide.apply(this, arguments);
71803             } else {
71804               show.apply(this, arguments);
71805             }
71806           }
71807
71808           return popover;
71809         }
71810
71811         function uiTooltip(klass) {
71812           var tooltip = uiPopover((klass || '') + ' tooltip').displayType('hover');
71813
71814           var _title = function _title() {
71815             var title = this.getAttribute('data-original-title');
71816
71817             if (title) {
71818               return title;
71819             } else {
71820               title = this.getAttribute('title');
71821               this.removeAttribute('title');
71822               this.setAttribute('data-original-title', title);
71823             }
71824
71825             return title;
71826           };
71827
71828           var _heading = utilFunctor(null);
71829
71830           var _keys = utilFunctor(null);
71831
71832           tooltip.title = function (val) {
71833             if (!arguments.length) return _title;
71834             _title = utilFunctor(val);
71835             return tooltip;
71836           };
71837
71838           tooltip.heading = function (val) {
71839             if (!arguments.length) return _heading;
71840             _heading = utilFunctor(val);
71841             return tooltip;
71842           };
71843
71844           tooltip.keys = function (val) {
71845             if (!arguments.length) return _keys;
71846             _keys = utilFunctor(val);
71847             return tooltip;
71848           };
71849
71850           tooltip.content(function () {
71851             var heading = _heading.apply(this, arguments);
71852
71853             var text = _title.apply(this, arguments);
71854
71855             var keys = _keys.apply(this, arguments);
71856
71857             return function (selection) {
71858               var headingSelect = selection.selectAll('.tooltip-heading').data(heading ? [heading] : []);
71859               headingSelect.exit().remove();
71860               headingSelect.enter().append('div').attr('class', 'tooltip-heading').merge(headingSelect).html(heading);
71861               var textSelect = selection.selectAll('.tooltip-text').data(text ? [text] : []);
71862               textSelect.exit().remove();
71863               textSelect.enter().append('div').attr('class', 'tooltip-text').merge(textSelect).html(text);
71864               var keyhintWrap = selection.selectAll('.keyhint-wrap').data(keys && keys.length ? [0] : []);
71865               keyhintWrap.exit().remove();
71866               var keyhintWrapEnter = keyhintWrap.enter().append('div').attr('class', 'keyhint-wrap');
71867               keyhintWrapEnter.append('span').html(_t.html('tooltip_keyhint'));
71868               keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
71869               keyhintWrap.selectAll('kbd.shortcut').data(keys && keys.length ? keys : []).enter().append('kbd').attr('class', 'shortcut').html(function (d) {
71870                 return d;
71871               });
71872             };
71873           });
71874           return tooltip;
71875         }
71876
71877         function uiEditMenu(context) {
71878           var dispatch = dispatch$8('toggled');
71879
71880           var _menu = select(null);
71881
71882           var _operations = []; // the position the menu should be displayed relative to
71883
71884           var _anchorLoc = [0, 0];
71885           var _anchorLocLonLat = [0, 0]; // a string indicating how the menu was opened
71886
71887           var _triggerType = '';
71888           var _vpTopMargin = 85; // viewport top margin
71889
71890           var _vpBottomMargin = 45; // viewport bottom margin
71891
71892           var _vpSideMargin = 35; // viewport side margin
71893
71894           var _menuTop = false;
71895
71896           var _menuHeight;
71897
71898           var _menuWidth; // hardcode these values to make menu positioning easier
71899
71900
71901           var _verticalPadding = 4; // see also `.edit-menu .tooltip` CSS; include margin
71902
71903           var _tooltipWidth = 210; // offset the menu slightly from the target location
71904
71905           var _menuSideMargin = 10;
71906           var _tooltips = [];
71907
71908           var editMenu = function editMenu(selection) {
71909             var isTouchMenu = _triggerType.includes('touch') || _triggerType.includes('pen');
71910
71911             var ops = _operations.filter(function (op) {
71912               return !isTouchMenu || !op.mouseOnly;
71913             });
71914
71915             if (!ops.length) return;
71916             _tooltips = []; // Position the menu above the anchor for stylus and finger input
71917             // since the mapper's hand likely obscures the screen below the anchor
71918
71919             _menuTop = isTouchMenu; // Show labels for touch input since there aren't hover tooltips
71920
71921             var showLabels = isTouchMenu;
71922             var buttonHeight = showLabels ? 32 : 34;
71923
71924             if (showLabels) {
71925               // Get a general idea of the width based on the length of the label
71926               _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function (op) {
71927                 return op.title.length;
71928               })));
71929             } else {
71930               _menuWidth = 44;
71931             }
71932
71933             _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
71934             _menu = selection.append('div').attr('class', 'edit-menu').classed('touch-menu', isTouchMenu).style('padding', _verticalPadding + 'px 0');
71935
71936             var buttons = _menu.selectAll('.edit-menu-item').data(ops); // enter
71937
71938
71939             var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
71940               return 'edit-menu-item edit-menu-item-' + d.id;
71941             }).style('height', buttonHeight + 'px').on('click', click) // don't listen for `mouseup` because we only care about non-mouse pointer types
71942             .on('pointerup', pointerup).on('pointerdown mousedown', function pointerdown(d3_event) {
71943               // don't let button presses also act as map input - #1869
71944               d3_event.stopPropagation();
71945             }).on('mouseenter.highlight', function (d3_event, d) {
71946               if (!d.relatedEntityIds || select(this).classed('disabled')) return;
71947               utilHighlightEntities(d.relatedEntityIds(), true, context);
71948             }).on('mouseleave.highlight', function (d3_event, d) {
71949               if (!d.relatedEntityIds) return;
71950               utilHighlightEntities(d.relatedEntityIds(), false, context);
71951             });
71952             buttonsEnter.each(function (d) {
71953               var tooltip = uiTooltip().heading(d.title).title(d.tooltip()).keys([d.keys[0]]);
71954
71955               _tooltips.push(tooltip);
71956
71957               select(this).call(tooltip).append('div').attr('class', 'icon-wrap').call(svgIcon('#iD-operation-' + d.id, 'operation'));
71958             });
71959
71960             if (showLabels) {
71961               buttonsEnter.append('span').attr('class', 'label').html(function (d) {
71962                 return d.title;
71963               });
71964             } // update
71965
71966
71967             buttonsEnter.merge(buttons).classed('disabled', function (d) {
71968               return d.disabled();
71969             });
71970             updatePosition();
71971             var initialScale = context.projection.scale();
71972             context.map().on('move.edit-menu', function () {
71973               if (initialScale !== context.projection.scale()) {
71974                 editMenu.close();
71975               }
71976             }).on('drawn.edit-menu', function (info) {
71977               if (info.full) updatePosition();
71978             });
71979             var lastPointerUpType; // `pointerup` is always called before `click`
71980
71981             function pointerup(d3_event) {
71982               lastPointerUpType = d3_event.pointerType;
71983             }
71984
71985             function click(d3_event, operation) {
71986               d3_event.stopPropagation();
71987
71988               if (operation.relatedEntityIds) {
71989                 utilHighlightEntities(operation.relatedEntityIds(), false, context);
71990               }
71991
71992               if (operation.disabled()) {
71993                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
71994                   // there are no tooltips for touch interactions so flash feedback instead
71995                   context.ui().flash.duration(4000).iconName('#iD-operation-' + operation.id).iconClass('operation disabled').label(operation.tooltip)();
71996                 }
71997               } else {
71998                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
71999                   context.ui().flash.duration(2000).iconName('#iD-operation-' + operation.id).iconClass('operation').label(operation.annotation() || operation.title)();
72000                 }
72001
72002                 operation();
72003                 editMenu.close();
72004               }
72005
72006               lastPointerUpType = null;
72007             }
72008
72009             dispatch.call('toggled', this, true);
72010           };
72011
72012           function updatePosition() {
72013             if (!_menu || _menu.empty()) return;
72014             var anchorLoc = context.projection(_anchorLocLonLat);
72015             var viewport = context.surfaceRect();
72016
72017             if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
72018               // close the menu if it's gone offscreen
72019               editMenu.close();
72020               return;
72021             }
72022
72023             var menuLeft = displayOnLeft(viewport);
72024             var offset = [0, 0];
72025             offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
72026
72027             if (_menuTop) {
72028               if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
72029                 // menu is near top viewport edge, shift downward
72030                 offset[1] = -anchorLoc[1] + _vpTopMargin;
72031               } else {
72032                 offset[1] = -_menuHeight;
72033               }
72034             } else {
72035               if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
72036                 // menu is near bottom viewport edge, shift upwards
72037                 offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
72038               } else {
72039                 offset[1] = 0;
72040               }
72041             }
72042
72043             var origin = geoVecAdd(anchorLoc, offset);
72044
72045             _menu.style('left', origin[0] + 'px').style('top', origin[1] + 'px');
72046
72047             var tooltipSide = tooltipPosition(viewport, menuLeft);
72048
72049             _tooltips.forEach(function (tooltip) {
72050               tooltip.placement(tooltipSide);
72051             });
72052
72053             function displayOnLeft(viewport) {
72054               if (_mainLocalizer.textDirection() === 'ltr') {
72055                 if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport.width - _vpSideMargin) {
72056                   // right menu would be too close to the right viewport edge, go left
72057                   return true;
72058                 } // prefer right menu
72059
72060
72061                 return false;
72062               } else {
72063                 // rtl
72064                 if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
72065                   // left menu would be too close to the left viewport edge, go right
72066                   return false;
72067                 } // prefer left menu
72068
72069
72070                 return true;
72071               }
72072             }
72073
72074             function tooltipPosition(viewport, menuLeft) {
72075               if (_mainLocalizer.textDirection() === 'ltr') {
72076                 if (menuLeft) {
72077                   // if there's not room for a right-side menu then there definitely
72078                   // isn't room for right-side tooltips
72079                   return 'left';
72080                 }
72081
72082                 if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport.width - _vpSideMargin) {
72083                   // right tooltips would be too close to the right viewport edge, go left
72084                   return 'left';
72085                 } // prefer right tooltips
72086
72087
72088                 return 'right';
72089               } else {
72090                 // rtl
72091                 if (!menuLeft) {
72092                   return 'right';
72093                 }
72094
72095                 if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
72096                   // left tooltips would be too close to the left viewport edge, go right
72097                   return 'right';
72098                 } // prefer left tooltips
72099
72100
72101                 return 'left';
72102               }
72103             }
72104           }
72105
72106           editMenu.close = function () {
72107             context.map().on('move.edit-menu', null).on('drawn.edit-menu', null);
72108
72109             _menu.remove();
72110
72111             _tooltips = [];
72112             dispatch.call('toggled', this, false);
72113           };
72114
72115           editMenu.anchorLoc = function (val) {
72116             if (!arguments.length) return _anchorLoc;
72117             _anchorLoc = val;
72118             _anchorLocLonLat = context.projection.invert(_anchorLoc);
72119             return editMenu;
72120           };
72121
72122           editMenu.triggerType = function (val) {
72123             if (!arguments.length) return _triggerType;
72124             _triggerType = val;
72125             return editMenu;
72126           };
72127
72128           editMenu.operations = function (val) {
72129             if (!arguments.length) return _operations;
72130             _operations = val;
72131             return editMenu;
72132           };
72133
72134           return utilRebind(editMenu, dispatch, 'on');
72135         }
72136
72137         function uiFeatureInfo(context) {
72138           function update(selection) {
72139             var features = context.features();
72140             var stats = features.stats();
72141             var count = 0;
72142             var hiddenList = features.hidden().map(function (k) {
72143               if (stats[k]) {
72144                 count += stats[k];
72145                 return _t('inspector.title_count', {
72146                   title: _t.html('feature.' + k + '.description'),
72147                   count: stats[k]
72148                 });
72149               }
72150
72151               return null;
72152             }).filter(Boolean);
72153             selection.html('');
72154
72155             if (hiddenList.length) {
72156               var tooltipBehavior = uiTooltip().placement('top').title(function () {
72157                 return hiddenList.join('<br/>');
72158               });
72159               selection.append('a').attr('class', 'chip').attr('href', '#').html(_t.html('feature_info.hidden_warning', {
72160                 count: count
72161               })).call(tooltipBehavior).on('click', function (d3_event) {
72162                 tooltipBehavior.hide();
72163                 d3_event.preventDefault(); // open the Map Data pane
72164
72165                 context.ui().togglePanes(context.container().select('.map-panes .map-data-pane'));
72166               });
72167             }
72168
72169             selection.classed('hide', !hiddenList.length);
72170           }
72171
72172           return function (selection) {
72173             update(selection);
72174             context.features().on('change.feature_info', function () {
72175               update(selection);
72176             });
72177           };
72178         }
72179
72180         function uiFlash(context) {
72181           var _flashTimer;
72182
72183           var _duration = 2000;
72184           var _iconName = '#iD-icon-no';
72185           var _iconClass = 'disabled';
72186           var _label = '';
72187
72188           function flash() {
72189             if (_flashTimer) {
72190               _flashTimer.stop();
72191             }
72192
72193             context.container().select('.main-footer-wrap').classed('footer-hide', true).classed('footer-show', false);
72194             context.container().select('.flash-wrap').classed('footer-hide', false).classed('footer-show', true);
72195             var content = context.container().select('.flash-wrap').selectAll('.flash-content').data([0]); // Enter
72196
72197             var contentEnter = content.enter().append('div').attr('class', 'flash-content');
72198             var iconEnter = contentEnter.append('svg').attr('class', 'flash-icon icon').append('g').attr('transform', 'translate(10,10)');
72199             iconEnter.append('circle').attr('r', 9);
72200             iconEnter.append('use').attr('transform', 'translate(-7,-7)').attr('width', '14').attr('height', '14');
72201             contentEnter.append('div').attr('class', 'flash-text'); // Update
72202
72203             content = content.merge(contentEnter);
72204             content.selectAll('.flash-icon').attr('class', 'icon flash-icon ' + (_iconClass || ''));
72205             content.selectAll('.flash-icon use').attr('xlink:href', _iconName);
72206             content.selectAll('.flash-text').attr('class', 'flash-text').html(_label);
72207             _flashTimer = d3_timeout(function () {
72208               _flashTimer = null;
72209               context.container().select('.main-footer-wrap').classed('footer-hide', false).classed('footer-show', true);
72210               context.container().select('.flash-wrap').classed('footer-hide', true).classed('footer-show', false);
72211             }, _duration);
72212             return content;
72213           }
72214
72215           flash.duration = function (_) {
72216             if (!arguments.length) return _duration;
72217             _duration = _;
72218             return flash;
72219           };
72220
72221           flash.label = function (_) {
72222             if (!arguments.length) return _label;
72223             _label = _;
72224             return flash;
72225           };
72226
72227           flash.iconName = function (_) {
72228             if (!arguments.length) return _iconName;
72229             _iconName = _;
72230             return flash;
72231           };
72232
72233           flash.iconClass = function (_) {
72234             if (!arguments.length) return _iconClass;
72235             _iconClass = _;
72236             return flash;
72237           };
72238
72239           return flash;
72240         }
72241
72242         function uiFullScreen(context) {
72243           var element = context.container().node(); // var button = d3_select(null);
72244
72245           function getFullScreenFn() {
72246             if (element.requestFullscreen) {
72247               return element.requestFullscreen;
72248             } else if (element.msRequestFullscreen) {
72249               return element.msRequestFullscreen;
72250             } else if (element.mozRequestFullScreen) {
72251               return element.mozRequestFullScreen;
72252             } else if (element.webkitRequestFullscreen) {
72253               return element.webkitRequestFullscreen;
72254             }
72255           }
72256
72257           function getExitFullScreenFn() {
72258             if (document.exitFullscreen) {
72259               return document.exitFullscreen;
72260             } else if (document.msExitFullscreen) {
72261               return document.msExitFullscreen;
72262             } else if (document.mozCancelFullScreen) {
72263               return document.mozCancelFullScreen;
72264             } else if (document.webkitExitFullscreen) {
72265               return document.webkitExitFullscreen;
72266             }
72267           }
72268
72269           function isFullScreen() {
72270             return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
72271           }
72272
72273           function isSupported() {
72274             return !!getFullScreenFn();
72275           }
72276
72277           function fullScreen(d3_event) {
72278             d3_event.preventDefault();
72279
72280             if (!isFullScreen()) {
72281               // button.classed('active', true);
72282               getFullScreenFn().apply(element);
72283             } else {
72284               // button.classed('active', false);
72285               getExitFullScreenFn().apply(document);
72286             }
72287           }
72288
72289           return function () {
72290             // selection) {
72291             if (!isSupported()) return; // button = selection.append('button')
72292             //     .attr('title', t('full_screen'))
72293             //     .on('click', fullScreen)
72294             //     .call(tooltip);
72295             // button.append('span')
72296             //     .attr('class', 'icon full-screen');
72297
72298             var detected = utilDetect();
72299             var keys = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
72300             context.keybinding().on(keys, fullScreen);
72301           };
72302         }
72303
72304         function uiGeolocate(context) {
72305           var _geolocationOptions = {
72306             // prioritize speed and power usage over precision
72307             enableHighAccuracy: false,
72308             // don't hang indefinitely getting the location
72309             timeout: 6000 // 6sec
72310
72311           };
72312
72313           var _locating = uiLoading(context).message(_t.html('geolocate.locating')).blocking(true);
72314
72315           var _layer = context.layers().layer('geolocate');
72316
72317           var _position;
72318
72319           var _extent;
72320
72321           var _timeoutID;
72322
72323           var _button = select(null);
72324
72325           function click() {
72326             if (context.inIntro()) return;
72327
72328             if (!_layer.enabled() && !_locating.isShown()) {
72329               // This timeout ensures that we still call finish() even if
72330               // the user declines to share their location in Firefox
72331               _timeoutID = setTimeout(error, 10000
72332               /* 10sec */
72333               );
72334               context.container().call(_locating); // get the latest position even if we already have one
72335
72336               navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
72337             } else {
72338               _locating.close();
72339
72340               _layer.enabled(null, false);
72341
72342               updateButtonState();
72343             }
72344           }
72345
72346           function zoomTo() {
72347             context.enter(modeBrowse(context));
72348             var map = context.map();
72349
72350             _layer.enabled(_position, true);
72351
72352             updateButtonState();
72353             map.centerZoomEase(_extent.center(), Math.min(20, map.extentZoom(_extent)));
72354           }
72355
72356           function success(geolocation) {
72357             _position = geolocation;
72358             var coords = _position.coords;
72359             _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
72360             zoomTo();
72361             finish();
72362           }
72363
72364           function error() {
72365             if (_position) {
72366               // use the position from a previous call if we have one
72367               zoomTo();
72368             } else {
72369               context.ui().flash.label(_t.html('geolocate.location_unavailable')).iconName('#iD-icon-geolocate')();
72370             }
72371
72372             finish();
72373           }
72374
72375           function finish() {
72376             _locating.close(); // unblock ui
72377
72378
72379             if (_timeoutID) {
72380               clearTimeout(_timeoutID);
72381             }
72382
72383             _timeoutID = undefined;
72384           }
72385
72386           function updateButtonState() {
72387             _button.classed('active', _layer.enabled());
72388           }
72389
72390           return function (selection) {
72391             if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
72392             _button = selection.append('button').on('click', click).call(svgIcon('#iD-icon-geolocate', 'light')).call(uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(_t.html('geolocate.title')).keys([_t('geolocate.key')]));
72393             context.keybinding().on(_t('geolocate.key'), click);
72394           };
72395         }
72396
72397         function uiPanelBackground(context) {
72398           var background = context.background();
72399           var _currSourceName = null;
72400           var _metadata = {};
72401           var _metadataKeys = ['zoom', 'vintage', 'source', 'description', 'resolution', 'accuracy'];
72402
72403           var debouncedRedraw = debounce(redraw, 250);
72404
72405           function redraw(selection) {
72406             var source = background.baseLayerSource();
72407             if (!source) return;
72408             var isDG = source.id.match(/^DigitalGlobe/i) !== null;
72409             var sourceLabel = source.label();
72410
72411             if (_currSourceName !== sourceLabel) {
72412               _currSourceName = sourceLabel;
72413               _metadata = {};
72414             }
72415
72416             selection.html('');
72417             var list = selection.append('ul').attr('class', 'background-info');
72418             list.append('li').html(_currSourceName);
72419
72420             _metadataKeys.forEach(function (k) {
72421               // DigitalGlobe vintage is available in raster layers for now.
72422               if (isDG && k === 'vintage') return;
72423               list.append('li').attr('class', 'background-info-list-' + k).classed('hide', !_metadata[k]).html(_t.html('info_panels.background.' + k) + ':').append('span').attr('class', 'background-info-span-' + k).html(_metadata[k]);
72424             });
72425
72426             debouncedGetMetadata(selection);
72427             var toggleTiles = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
72428             selection.append('a').html(_t.html('info_panels.background.' + toggleTiles)).attr('href', '#').attr('class', 'button button-toggle-tiles').on('click', function (d3_event) {
72429               d3_event.preventDefault();
72430               context.setDebug('tile', !context.getDebug('tile'));
72431               selection.call(redraw);
72432             });
72433
72434             if (isDG) {
72435               var key = source.id + '-vintage';
72436               var sourceVintage = context.background().findSource(key);
72437               var showsVintage = context.background().showsLayer(sourceVintage);
72438               var toggleVintage = showsVintage ? 'hide_vintage' : 'show_vintage';
72439               selection.append('a').html(_t.html('info_panels.background.' + toggleVintage)).attr('href', '#').attr('class', 'button button-toggle-vintage').on('click', function (d3_event) {
72440                 d3_event.preventDefault();
72441                 context.background().toggleOverlayLayer(sourceVintage);
72442                 selection.call(redraw);
72443               });
72444             } // disable if necessary
72445
72446
72447             ['DigitalGlobe-Premium', 'DigitalGlobe-Standard'].forEach(function (layerId) {
72448               if (source.id !== layerId) {
72449                 var key = layerId + '-vintage';
72450                 var sourceVintage = context.background().findSource(key);
72451
72452                 if (context.background().showsLayer(sourceVintage)) {
72453                   context.background().toggleOverlayLayer(sourceVintage);
72454                 }
72455               }
72456             });
72457           }
72458
72459           var debouncedGetMetadata = debounce(getMetadata, 250);
72460
72461           function getMetadata(selection) {
72462             var tile = context.container().select('.layer-background img.tile-center'); // tile near viewport center
72463
72464             if (tile.empty()) return;
72465             var sourceName = _currSourceName;
72466             var d = tile.datum();
72467             var zoom = d && d.length >= 3 && d[2] || Math.floor(context.map().zoom());
72468             var center = context.map().center(); // update zoom
72469
72470             _metadata.zoom = String(zoom);
72471             selection.selectAll('.background-info-list-zoom').classed('hide', false).selectAll('.background-info-span-zoom').html(_metadata.zoom);
72472             if (!d || !d.length >= 3) return;
72473             background.baseLayerSource().getMetadata(center, d, function (err, result) {
72474               if (err || _currSourceName !== sourceName) return; // update vintage
72475
72476               var vintage = result.vintage;
72477               _metadata.vintage = vintage && vintage.range || _t('info_panels.background.unknown');
72478               selection.selectAll('.background-info-list-vintage').classed('hide', false).selectAll('.background-info-span-vintage').html(_metadata.vintage); // update other _metadata
72479
72480               _metadataKeys.forEach(function (k) {
72481                 if (k === 'zoom' || k === 'vintage') return; // done already
72482
72483                 var val = result[k];
72484                 _metadata[k] = val;
72485                 selection.selectAll('.background-info-list-' + k).classed('hide', !val).selectAll('.background-info-span-' + k).html(val);
72486               });
72487             });
72488           }
72489
72490           var panel = function panel(selection) {
72491             selection.call(redraw);
72492             context.map().on('drawn.info-background', function () {
72493               selection.call(debouncedRedraw);
72494             }).on('move.info-background', function () {
72495               selection.call(debouncedGetMetadata);
72496             });
72497           };
72498
72499           panel.off = function () {
72500             context.map().on('drawn.info-background', null).on('move.info-background', null);
72501           };
72502
72503           panel.id = 'background';
72504           panel.label = _t.html('info_panels.background.title');
72505           panel.key = _t('info_panels.background.key');
72506           return panel;
72507         }
72508
72509         function uiPanelHistory(context) {
72510           var osm;
72511
72512           function displayTimestamp(timestamp) {
72513             if (!timestamp) return _t('info_panels.history.unknown');
72514             var options = {
72515               day: 'numeric',
72516               month: 'short',
72517               year: 'numeric',
72518               hour: 'numeric',
72519               minute: 'numeric',
72520               second: 'numeric'
72521             };
72522             var d = new Date(timestamp);
72523             if (isNaN(d.getTime())) return _t('info_panels.history.unknown');
72524             return d.toLocaleString(_mainLocalizer.localeCode(), options);
72525           }
72526
72527           function displayUser(selection, userName) {
72528             if (!userName) {
72529               selection.append('span').html(_t.html('info_panels.history.unknown'));
72530               return;
72531             }
72532
72533             selection.append('span').attr('class', 'user-name').html(userName);
72534             var links = selection.append('div').attr('class', 'links');
72535
72536             if (osm) {
72537               links.append('a').attr('class', 'user-osm-link').attr('href', osm.userURL(userName)).attr('target', '_blank').html('OSM');
72538             }
72539
72540             links.append('a').attr('class', 'user-hdyc-link').attr('href', 'https://hdyc.neis-one.org/?' + userName).attr('target', '_blank').attr('tabindex', -1).html('HDYC');
72541           }
72542
72543           function displayChangeset(selection, changeset) {
72544             if (!changeset) {
72545               selection.append('span').html(_t.html('info_panels.history.unknown'));
72546               return;
72547             }
72548
72549             selection.append('span').attr('class', 'changeset-id').html(changeset);
72550             var links = selection.append('div').attr('class', 'links');
72551
72552             if (osm) {
72553               links.append('a').attr('class', 'changeset-osm-link').attr('href', osm.changesetURL(changeset)).attr('target', '_blank').html('OSM');
72554             }
72555
72556             links.append('a').attr('class', 'changeset-osmcha-link').attr('href', 'https://osmcha.org/changesets/' + changeset).attr('target', '_blank').html('OSMCha');
72557             links.append('a').attr('class', 'changeset-achavi-link').attr('href', 'https://overpass-api.de/achavi/?changeset=' + changeset).attr('target', '_blank').html('Achavi');
72558           }
72559
72560           function redraw(selection) {
72561             var selectedNoteID = context.selectedNoteID();
72562             osm = context.connection();
72563             var selected, note, entity;
72564
72565             if (selectedNoteID && osm) {
72566               // selected 1 note
72567               selected = [_t('note.note') + ' ' + selectedNoteID];
72568               note = osm.getNote(selectedNoteID);
72569             } else {
72570               // selected 1..n entities
72571               selected = context.selectedIDs().filter(function (e) {
72572                 return context.hasEntity(e);
72573               });
72574
72575               if (selected.length) {
72576                 entity = context.entity(selected[0]);
72577               }
72578             }
72579
72580             var singular = selected.length === 1 ? selected[0] : null;
72581             selection.html('');
72582             selection.append('h4').attr('class', 'history-heading').html(singular || _t.html('info_panels.selected', {
72583               n: selected.length
72584             }));
72585             if (!singular) return;
72586
72587             if (entity) {
72588               selection.call(redrawEntity, entity);
72589             } else if (note) {
72590               selection.call(redrawNote, note);
72591             }
72592           }
72593
72594           function redrawNote(selection, note) {
72595             if (!note || note.isNew()) {
72596               selection.append('div').html(_t.html('info_panels.history.note_no_history'));
72597               return;
72598             }
72599
72600             var list = selection.append('ul');
72601             list.append('li').html(_t.html('info_panels.history.note_comments') + ':').append('span').html(note.comments.length);
72602
72603             if (note.comments.length) {
72604               list.append('li').html(_t.html('info_panels.history.note_created_date') + ':').append('span').html(displayTimestamp(note.comments[0].date));
72605               list.append('li').html(_t.html('info_panels.history.note_created_user') + ':').call(displayUser, note.comments[0].user);
72606             }
72607
72608             if (osm) {
72609               selection.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').html(_t.html('info_panels.history.note_link_text'));
72610             }
72611           }
72612
72613           function redrawEntity(selection, entity) {
72614             if (!entity || entity.isNew()) {
72615               selection.append('div').html(_t.html('info_panels.history.no_history'));
72616               return;
72617             }
72618
72619             var links = selection.append('div').attr('class', 'links');
72620
72621             if (osm) {
72622               links.append('a').attr('class', 'view-history-on-osm').attr('href', osm.historyURL(entity)).attr('target', '_blank').attr('title', _t('info_panels.history.link_text')).html('OSM');
72623             }
72624
72625             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).html('PeWu');
72626             var list = selection.append('ul');
72627             list.append('li').html(_t.html('info_panels.history.version') + ':').append('span').html(entity.version);
72628             list.append('li').html(_t.html('info_panels.history.last_edit') + ':').append('span').html(displayTimestamp(entity.timestamp));
72629             list.append('li').html(_t.html('info_panels.history.edited_by') + ':').call(displayUser, entity.user);
72630             list.append('li').html(_t.html('info_panels.history.changeset') + ':').call(displayChangeset, entity.changeset);
72631           }
72632
72633           var panel = function panel(selection) {
72634             selection.call(redraw);
72635             context.map().on('drawn.info-history', function () {
72636               selection.call(redraw);
72637             });
72638             context.on('enter.info-history', function () {
72639               selection.call(redraw);
72640             });
72641           };
72642
72643           panel.off = function () {
72644             context.map().on('drawn.info-history', null);
72645             context.on('enter.info-history', null);
72646           };
72647
72648           panel.id = 'history';
72649           panel.label = _t.html('info_panels.history.title');
72650           panel.key = _t('info_panels.history.key');
72651           return panel;
72652         }
72653
72654         var OSM_PRECISION = 7;
72655         /**
72656          * Returns a localized representation of the given length measurement.
72657          *
72658          * @param {Number} m area in meters
72659          * @param {Boolean} isImperial true for U.S. customary units; false for metric
72660          */
72661
72662         function displayLength(m, isImperial) {
72663           var d = m * (isImperial ? 3.28084 : 1);
72664           var unit;
72665
72666           if (isImperial) {
72667             if (d >= 5280) {
72668               d /= 5280;
72669               unit = 'miles';
72670             } else {
72671               unit = 'feet';
72672             }
72673           } else {
72674             if (d >= 1000) {
72675               d /= 1000;
72676               unit = 'kilometers';
72677             } else {
72678               unit = 'meters';
72679             }
72680           }
72681
72682           return _t('units.' + unit, {
72683             quantity: d.toLocaleString(_mainLocalizer.localeCode(), {
72684               maximumSignificantDigits: 4
72685             })
72686           });
72687         }
72688         /**
72689          * Returns a localized representation of the given area measurement.
72690          *
72691          * @param {Number} m2 area in square meters
72692          * @param {Boolean} isImperial true for U.S. customary units; false for metric
72693          */
72694
72695         function displayArea(m2, isImperial) {
72696           var locale = _mainLocalizer.localeCode();
72697           var d = m2 * (isImperial ? 10.7639111056 : 1);
72698           var d1, d2, area;
72699           var unit1 = '';
72700           var unit2 = '';
72701
72702           if (isImperial) {
72703             if (d >= 6969600) {
72704               // > 0.25mi² show mi²
72705               d1 = d / 27878400;
72706               unit1 = 'square_miles';
72707             } else {
72708               d1 = d;
72709               unit1 = 'square_feet';
72710             }
72711
72712             if (d > 4356 && d < 43560000) {
72713               // 0.1 - 1000 acres
72714               d2 = d / 43560;
72715               unit2 = 'acres';
72716             }
72717           } else {
72718             if (d >= 250000) {
72719               // > 0.25km² show km²
72720               d1 = d / 1000000;
72721               unit1 = 'square_kilometers';
72722             } else {
72723               d1 = d;
72724               unit1 = 'square_meters';
72725             }
72726
72727             if (d > 1000 && d < 10000000) {
72728               // 0.1 - 1000 hectares
72729               d2 = d / 10000;
72730               unit2 = 'hectares';
72731             }
72732           }
72733
72734           area = _t('units.' + unit1, {
72735             quantity: d1.toLocaleString(locale, {
72736               maximumSignificantDigits: 4
72737             })
72738           });
72739
72740           if (d2) {
72741             return _t('units.area_pair', {
72742               area1: area,
72743               area2: _t('units.' + unit2, {
72744                 quantity: d2.toLocaleString(locale, {
72745                   maximumSignificantDigits: 2
72746                 })
72747               })
72748             });
72749           } else {
72750             return area;
72751           }
72752         }
72753
72754         function wrap(x, min, max) {
72755           var d = max - min;
72756           return ((x - min) % d + d) % d + min;
72757         }
72758
72759         function clamp(x, min, max) {
72760           return Math.max(min, Math.min(x, max));
72761         }
72762
72763         function displayCoordinate(deg, pos, neg) {
72764           var locale = _mainLocalizer.localeCode();
72765           var min = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60;
72766           var sec = (min - Math.floor(min)) * 60;
72767           var displayDegrees = _t('units.arcdegrees', {
72768             quantity: Math.floor(Math.abs(deg)).toLocaleString(locale)
72769           });
72770           var displayCoordinate;
72771
72772           if (Math.floor(sec) > 0) {
72773             displayCoordinate = displayDegrees + _t('units.arcminutes', {
72774               quantity: Math.floor(min).toLocaleString(locale)
72775             }) + _t('units.arcseconds', {
72776               quantity: Math.round(sec).toLocaleString(locale)
72777             });
72778           } else if (Math.floor(min) > 0) {
72779             displayCoordinate = displayDegrees + _t('units.arcminutes', {
72780               quantity: Math.round(min).toLocaleString(locale)
72781             });
72782           } else {
72783             displayCoordinate = _t('units.arcdegrees', {
72784               quantity: Math.round(Math.abs(deg)).toLocaleString(locale)
72785             });
72786           }
72787
72788           if (deg === 0) {
72789             return displayCoordinate;
72790           } else {
72791             return _t('units.coordinate', {
72792               coordinate: displayCoordinate,
72793               direction: _t('units.' + (deg > 0 ? pos : neg))
72794             });
72795           }
72796         }
72797         /**
72798          * Returns given coordinate pair in degree-minute-second format.
72799          *
72800          * @param {Array<Number>} coord longitude and latitude
72801          */
72802
72803
72804         function dmsCoordinatePair(coord) {
72805           return _t('units.coordinate_pair', {
72806             latitude: displayCoordinate(clamp(coord[1], -90, 90), 'north', 'south'),
72807             longitude: displayCoordinate(wrap(coord[0], -180, 180), 'east', 'west')
72808           });
72809         }
72810         /**
72811          * Returns the given coordinate pair in decimal format.
72812          * note: unlocalized to avoid comma ambiguity - see #4765
72813          *
72814          * @param {Array<Number>} coord longitude and latitude
72815          */
72816
72817         function decimalCoordinatePair(coord) {
72818           return _t('units.coordinate_pair', {
72819             latitude: clamp(coord[1], -90, 90).toFixed(OSM_PRECISION),
72820             longitude: wrap(coord[0], -180, 180).toFixed(OSM_PRECISION)
72821           });
72822         }
72823
72824         function uiPanelLocation(context) {
72825           var currLocation = '';
72826
72827           function redraw(selection) {
72828             selection.html('');
72829             var list = selection.append('ul'); // Mouse coordinates
72830
72831             var coord = context.map().mouseCoordinates();
72832
72833             if (coord.some(isNaN)) {
72834               coord = context.map().center();
72835             }
72836
72837             list.append('li').html(dmsCoordinatePair(coord)).append('li').html(decimalCoordinatePair(coord)); // Location Info
72838
72839             selection.append('div').attr('class', 'location-info').html(currLocation || ' ');
72840             debouncedGetLocation(selection, coord);
72841           }
72842
72843           var debouncedGetLocation = debounce(getLocation, 250);
72844
72845           function getLocation(selection, coord) {
72846             if (!services.geocoder) {
72847               currLocation = _t('info_panels.location.unknown_location');
72848               selection.selectAll('.location-info').html(currLocation);
72849             } else {
72850               services.geocoder.reverse(coord, function (err, result) {
72851                 currLocation = result ? result.display_name : _t('info_panels.location.unknown_location');
72852                 selection.selectAll('.location-info').html(currLocation);
72853               });
72854             }
72855           }
72856
72857           var panel = function panel(selection) {
72858             selection.call(redraw);
72859             context.surface().on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'move.info-location', function () {
72860               selection.call(redraw);
72861             });
72862           };
72863
72864           panel.off = function () {
72865             context.surface().on('.info-location', null);
72866           };
72867
72868           panel.id = 'location';
72869           panel.label = _t.html('info_panels.location.title');
72870           panel.key = _t('info_panels.location.key');
72871           return panel;
72872         }
72873
72874         function uiPanelMeasurement(context) {
72875           function radiansToMeters(r) {
72876             // using WGS84 authalic radius (6371007.1809 m)
72877             return r * 6371007.1809;
72878           }
72879
72880           function steradiansToSqmeters(r) {
72881             // http://gis.stackexchange.com/a/124857/40446
72882             return r / (4 * Math.PI) * 510065621724000;
72883           }
72884
72885           function toLineString(feature) {
72886             if (feature.type === 'LineString') return feature;
72887             var result = {
72888               type: 'LineString',
72889               coordinates: []
72890             };
72891
72892             if (feature.type === 'Polygon') {
72893               result.coordinates = feature.coordinates[0];
72894             } else if (feature.type === 'MultiPolygon') {
72895               result.coordinates = feature.coordinates[0][0];
72896             }
72897
72898             return result;
72899           }
72900
72901           var _isImperial = !_mainLocalizer.usesMetric();
72902
72903           function redraw(selection) {
72904             var graph = context.graph();
72905             var selectedNoteID = context.selectedNoteID();
72906             var osm = services.osm;
72907             var localeCode = _mainLocalizer.localeCode();
72908             var heading;
72909             var center, location, centroid;
72910             var closed, geometry;
72911             var totalNodeCount,
72912                 length = 0,
72913                 area = 0,
72914                 distance;
72915
72916             if (selectedNoteID && osm) {
72917               // selected 1 note
72918               var note = osm.getNote(selectedNoteID);
72919               heading = _t('note.note') + ' ' + selectedNoteID;
72920               location = note.loc;
72921               geometry = 'note';
72922             } else {
72923               // selected 1..n entities
72924               var selectedIDs = context.selectedIDs().filter(function (id) {
72925                 return context.hasEntity(id);
72926               });
72927               var selected = selectedIDs.map(function (id) {
72928                 return context.entity(id);
72929               });
72930               heading = selected.length === 1 ? selected[0].id : _t('info_panels.selected', {
72931                 n: selected.length
72932               });
72933
72934               if (selected.length) {
72935                 var extent = geoExtent();
72936
72937                 for (var i in selected) {
72938                   var entity = selected[i];
72939
72940                   extent._extend(entity.extent(graph));
72941
72942                   geometry = entity.geometry(graph);
72943
72944                   if (geometry === 'line' || geometry === 'area') {
72945                     closed = entity.type === 'relation' || entity.isClosed() && !entity.isDegenerate();
72946                     var feature = entity.asGeoJSON(graph);
72947                     length += radiansToMeters(d3_geoLength(toLineString(feature)));
72948                     centroid = d3_geoPath(context.projection).centroid(entity.asGeoJSON(graph));
72949                     centroid = centroid && context.projection.invert(centroid);
72950
72951                     if (!centroid || !isFinite(centroid[0]) || !isFinite(centroid[1])) {
72952                       centroid = entity.extent(graph).center();
72953                     }
72954
72955                     if (closed) {
72956                       area += steradiansToSqmeters(entity.area(graph));
72957                     }
72958                   }
72959                 }
72960
72961                 if (selected.length > 1) {
72962                   geometry = null;
72963                   closed = null;
72964                   centroid = null;
72965                 }
72966
72967                 if (selected.length === 2 && selected[0].type === 'node' && selected[1].type === 'node') {
72968                   distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
72969                 }
72970
72971                 if (selected.length === 1 && selected[0].type === 'node') {
72972                   location = selected[0].loc;
72973                 } else {
72974                   totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
72975                 }
72976
72977                 if (!location && !centroid) {
72978                   center = extent.center();
72979                 }
72980               }
72981             }
72982
72983             selection.html('');
72984
72985             if (heading) {
72986               selection.append('h4').attr('class', 'measurement-heading').html(heading);
72987             }
72988
72989             var list = selection.append('ul');
72990             var coordItem;
72991
72992             if (geometry) {
72993               list.append('li').html(_t.html('info_panels.measurement.geometry') + ':').append('span').html(closed ? _t('info_panels.measurement.closed_' + geometry) : _t('geometry.' + geometry));
72994             }
72995
72996             if (totalNodeCount) {
72997               list.append('li').html(_t.html('info_panels.measurement.node_count') + ':').append('span').html(totalNodeCount.toLocaleString(localeCode));
72998             }
72999
73000             if (area) {
73001               list.append('li').html(_t.html('info_panels.measurement.area') + ':').append('span').html(displayArea(area, _isImperial));
73002             }
73003
73004             if (length) {
73005               list.append('li').html(_t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':').append('span').html(displayLength(length, _isImperial));
73006             }
73007
73008             if (typeof distance === 'number') {
73009               list.append('li').html(_t.html('info_panels.measurement.distance') + ':').append('span').html(displayLength(distance, _isImperial));
73010             }
73011
73012             if (location) {
73013               coordItem = list.append('li').html(_t.html('info_panels.measurement.location') + ':');
73014               coordItem.append('span').html(dmsCoordinatePair(location));
73015               coordItem.append('span').html(decimalCoordinatePair(location));
73016             }
73017
73018             if (centroid) {
73019               coordItem = list.append('li').html(_t.html('info_panels.measurement.centroid') + ':');
73020               coordItem.append('span').html(dmsCoordinatePair(centroid));
73021               coordItem.append('span').html(decimalCoordinatePair(centroid));
73022             }
73023
73024             if (center) {
73025               coordItem = list.append('li').html(_t.html('info_panels.measurement.center') + ':');
73026               coordItem.append('span').html(dmsCoordinatePair(center));
73027               coordItem.append('span').html(decimalCoordinatePair(center));
73028             }
73029
73030             if (length || area || typeof distance === 'number') {
73031               var toggle = _isImperial ? 'imperial' : 'metric';
73032               selection.append('a').html(_t.html('info_panels.measurement.' + toggle)).attr('href', '#').attr('class', 'button button-toggle-units').on('click', function (d3_event) {
73033                 d3_event.preventDefault();
73034                 _isImperial = !_isImperial;
73035                 selection.call(redraw);
73036               });
73037             }
73038           }
73039
73040           var panel = function panel(selection) {
73041             selection.call(redraw);
73042             context.map().on('drawn.info-measurement', function () {
73043               selection.call(redraw);
73044             });
73045             context.on('enter.info-measurement', function () {
73046               selection.call(redraw);
73047             });
73048           };
73049
73050           panel.off = function () {
73051             context.map().on('drawn.info-measurement', null);
73052             context.on('enter.info-measurement', null);
73053           };
73054
73055           panel.id = 'measurement';
73056           panel.label = _t.html('info_panels.measurement.title');
73057           panel.key = _t('info_panels.measurement.key');
73058           return panel;
73059         }
73060
73061         var uiInfoPanels = {
73062           background: uiPanelBackground,
73063           history: uiPanelHistory,
73064           location: uiPanelLocation,
73065           measurement: uiPanelMeasurement
73066         };
73067
73068         function uiInfo(context) {
73069           var ids = Object.keys(uiInfoPanels);
73070           var wasActive = ['measurement'];
73071           var panels = {};
73072           var active = {}; // create panels
73073
73074           ids.forEach(function (k) {
73075             if (!panels[k]) {
73076               panels[k] = uiInfoPanels[k](context);
73077               active[k] = false;
73078             }
73079           });
73080
73081           function info(selection) {
73082             function redraw() {
73083               var activeids = ids.filter(function (k) {
73084                 return active[k];
73085               }).sort();
73086               var containers = infoPanels.selectAll('.panel-container').data(activeids, function (k) {
73087                 return k;
73088               });
73089               containers.exit().style('opacity', 1).transition().duration(200).style('opacity', 0).on('end', function (d) {
73090                 select(this).call(panels[d].off).remove();
73091               });
73092               var enter = containers.enter().append('div').attr('class', function (d) {
73093                 return 'fillD2 panel-container panel-container-' + d;
73094               });
73095               enter.style('opacity', 0).transition().duration(200).style('opacity', 1);
73096               var title = enter.append('div').attr('class', 'panel-title fillD2');
73097               title.append('h3').html(function (d) {
73098                 return panels[d].label;
73099               });
73100               title.append('button').attr('class', 'close').on('click', function (d3_event, d) {
73101                 d3_event.stopImmediatePropagation();
73102                 d3_event.preventDefault();
73103                 info.toggle(d);
73104               }).call(svgIcon('#iD-icon-close'));
73105               enter.append('div').attr('class', function (d) {
73106                 return 'panel-content panel-content-' + d;
73107               }); // redraw the panels
73108
73109               infoPanels.selectAll('.panel-content').each(function (d) {
73110                 select(this).call(panels[d]);
73111               });
73112             }
73113
73114             info.toggle = function (which) {
73115               var activeids = ids.filter(function (k) {
73116                 return active[k];
73117               });
73118
73119               if (which) {
73120                 // toggle one
73121                 active[which] = !active[which];
73122
73123                 if (activeids.length === 1 && activeids[0] === which) {
73124                   // none active anymore
73125                   wasActive = [which];
73126                 }
73127
73128                 context.container().select('.' + which + '-panel-toggle-item').classed('active', active[which]).select('input').property('checked', active[which]);
73129               } else {
73130                 // toggle all
73131                 if (activeids.length) {
73132                   wasActive = activeids;
73133                   activeids.forEach(function (k) {
73134                     active[k] = false;
73135                   });
73136                 } else {
73137                   wasActive.forEach(function (k) {
73138                     active[k] = true;
73139                   });
73140                 }
73141               }
73142
73143               redraw();
73144             };
73145
73146             var infoPanels = selection.selectAll('.info-panels').data([0]);
73147             infoPanels = infoPanels.enter().append('div').attr('class', 'info-panels').merge(infoPanels);
73148             redraw();
73149             context.keybinding().on(uiCmd('⌘' + _t('info_panels.key')), function (d3_event) {
73150               d3_event.stopImmediatePropagation();
73151               d3_event.preventDefault();
73152               info.toggle();
73153             });
73154             ids.forEach(function (k) {
73155               var key = _t('info_panels.' + k + '.key', {
73156                 "default": null
73157               });
73158               if (!key) return;
73159               context.keybinding().on(uiCmd('⌘⇧' + key), function (d3_event) {
73160                 d3_event.stopImmediatePropagation();
73161                 d3_event.preventDefault();
73162                 info.toggle(k);
73163               });
73164             });
73165           }
73166
73167           return info;
73168         }
73169
73170         function pointBox(loc, context) {
73171           var rect = context.surfaceRect();
73172           var point = context.curtainProjection(loc);
73173           return {
73174             left: point[0] + rect.left - 40,
73175             top: point[1] + rect.top - 60,
73176             width: 80,
73177             height: 90
73178           };
73179         }
73180         function pad(locOrBox, padding, context) {
73181           var box;
73182
73183           if (locOrBox instanceof Array) {
73184             var rect = context.surfaceRect();
73185             var point = context.curtainProjection(locOrBox);
73186             box = {
73187               left: point[0] + rect.left,
73188               top: point[1] + rect.top
73189             };
73190           } else {
73191             box = locOrBox;
73192           }
73193
73194           return {
73195             left: box.left - padding,
73196             top: box.top - padding,
73197             width: (box.width || 0) + 2 * padding,
73198             height: (box.width || 0) + 2 * padding
73199           };
73200         }
73201         function icon(name, svgklass, useklass) {
73202           return '<svg class="icon ' + (svgklass || '') + '">' + '<use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : '') + '></use></svg>';
73203         }
73204         var helpStringReplacements; // Returns the localized HTML element for `id` with a standardized set of icon, key, and
73205         // label replacements suitable for tutorials and documentation. Optionally supplemented
73206         // with custom `replacements`
73207
73208         function helpHtml(id, replacements) {
73209           // only load these the first time
73210           if (!helpStringReplacements) {
73211             helpStringReplacements = {
73212               // insert icons corresponding to various UI elements
73213               point_icon: icon('#iD-icon-point', 'inline'),
73214               line_icon: icon('#iD-icon-line', 'inline'),
73215               area_icon: icon('#iD-icon-area', 'inline'),
73216               note_icon: icon('#iD-icon-note', 'inline add-note'),
73217               plus: icon('#iD-icon-plus', 'inline'),
73218               minus: icon('#iD-icon-minus', 'inline'),
73219               layers_icon: icon('#iD-icon-layers', 'inline'),
73220               data_icon: icon('#iD-icon-data', 'inline'),
73221               inspect: icon('#iD-icon-inspect', 'inline'),
73222               help_icon: icon('#iD-icon-help', 'inline'),
73223               undo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo', 'inline'),
73224               redo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-undo' : '#iD-icon-redo', 'inline'),
73225               save_icon: icon('#iD-icon-save', 'inline'),
73226               // operation icons
73227               circularize_icon: icon('#iD-operation-circularize', 'inline operation'),
73228               continue_icon: icon('#iD-operation-continue', 'inline operation'),
73229               copy_icon: icon('#iD-operation-copy', 'inline operation'),
73230               delete_icon: icon('#iD-operation-delete', 'inline operation'),
73231               disconnect_icon: icon('#iD-operation-disconnect', 'inline operation'),
73232               downgrade_icon: icon('#iD-operation-downgrade', 'inline operation'),
73233               extract_icon: icon('#iD-operation-extract', 'inline operation'),
73234               merge_icon: icon('#iD-operation-merge', 'inline operation'),
73235               move_icon: icon('#iD-operation-move', 'inline operation'),
73236               orthogonalize_icon: icon('#iD-operation-orthogonalize', 'inline operation'),
73237               paste_icon: icon('#iD-operation-paste', 'inline operation'),
73238               reflect_long_icon: icon('#iD-operation-reflect-long', 'inline operation'),
73239               reflect_short_icon: icon('#iD-operation-reflect-short', 'inline operation'),
73240               reverse_icon: icon('#iD-operation-reverse', 'inline operation'),
73241               rotate_icon: icon('#iD-operation-rotate', 'inline operation'),
73242               split_icon: icon('#iD-operation-split', 'inline operation'),
73243               straighten_icon: icon('#iD-operation-straighten', 'inline operation'),
73244               // interaction icons
73245               leftclick: icon('#iD-walkthrough-mouse-left', 'inline operation'),
73246               rightclick: icon('#iD-walkthrough-mouse-right', 'inline operation'),
73247               mousewheel_icon: icon('#iD-walkthrough-mousewheel', 'inline operation'),
73248               tap_icon: icon('#iD-walkthrough-tap', 'inline operation'),
73249               doubletap_icon: icon('#iD-walkthrough-doubletap', 'inline operation'),
73250               longpress_icon: icon('#iD-walkthrough-longpress', 'inline operation'),
73251               touchdrag_icon: icon('#iD-walkthrough-touchdrag', 'inline operation'),
73252               pinch_icon: icon('#iD-walkthrough-pinch-apart', 'inline operation'),
73253               // insert keys; may be localized and platform-dependent
73254               shift: uiCmd.display('⇧'),
73255               alt: uiCmd.display('⌥'),
73256               "return": uiCmd.display('↵'),
73257               esc: _t.html('shortcuts.key.esc'),
73258               space: _t.html('shortcuts.key.space'),
73259               add_note_key: _t.html('modes.add_note.key'),
73260               help_key: _t.html('help.key'),
73261               shortcuts_key: _t.html('shortcuts.toggle.key'),
73262               // reference localized UI labels directly so that they'll always match
73263               save: _t.html('save.title'),
73264               undo: _t.html('undo.title'),
73265               redo: _t.html('redo.title'),
73266               upload: _t.html('commit.save'),
73267               point: _t.html('modes.add_point.title'),
73268               line: _t.html('modes.add_line.title'),
73269               area: _t.html('modes.add_area.title'),
73270               note: _t.html('modes.add_note.label'),
73271               circularize: _t.html('operations.circularize.title'),
73272               "continue": _t.html('operations.continue.title'),
73273               copy: _t.html('operations.copy.title'),
73274               "delete": _t.html('operations.delete.title'),
73275               disconnect: _t.html('operations.disconnect.title'),
73276               downgrade: _t.html('operations.downgrade.title'),
73277               extract: _t.html('operations.extract.title'),
73278               merge: _t.html('operations.merge.title'),
73279               move: _t.html('operations.move.title'),
73280               orthogonalize: _t.html('operations.orthogonalize.title'),
73281               paste: _t.html('operations.paste.title'),
73282               reflect_long: _t.html('operations.reflect.title.long'),
73283               reflect_short: _t.html('operations.reflect.title.short'),
73284               reverse: _t.html('operations.reverse.title'),
73285               rotate: _t.html('operations.rotate.title'),
73286               split: _t.html('operations.split.title'),
73287               straighten: _t.html('operations.straighten.title'),
73288               map_data: _t.html('map_data.title'),
73289               osm_notes: _t.html('map_data.layers.notes.title'),
73290               fields: _t.html('inspector.fields'),
73291               tags: _t.html('inspector.tags'),
73292               relations: _t.html('inspector.relations'),
73293               new_relation: _t.html('inspector.new_relation'),
73294               turn_restrictions: _t.html('_tagging.presets.fields.restrictions.label'),
73295               background_settings: _t.html('background.description'),
73296               imagery_offset: _t.html('background.fix_misalignment'),
73297               start_the_walkthrough: _t.html('splash.walkthrough'),
73298               help: _t.html('help.title'),
73299               ok: _t.html('intro.ok')
73300             };
73301           }
73302
73303           var reps;
73304
73305           if (replacements) {
73306             reps = Object.assign(replacements, helpStringReplacements);
73307           } else {
73308             reps = helpStringReplacements;
73309           }
73310
73311           return _t.html(id, reps) // use keyboard key styling for shortcuts
73312           .replace(/\`(.*?)\`/g, '<kbd>$1</kbd>');
73313         }
73314
73315         function slugify(text) {
73316           return text.toString().toLowerCase().replace(/\s+/g, '-') // Replace spaces with -
73317           .replace(/[^\w\-]+/g, '') // Remove all non-word chars
73318           .replace(/\-\-+/g, '-') // Replace multiple - with single -
73319           .replace(/^-+/, '') // Trim - from start of text
73320           .replace(/-+$/, ''); // Trim - from end of text
73321         } // console warning for missing walkthrough names
73322
73323
73324         var missingStrings = {};
73325
73326         function checkKey(key, text) {
73327           if (_t(key, {
73328             "default": undefined
73329           }) === undefined) {
73330             if (missingStrings.hasOwnProperty(key)) return; // warn once
73331
73332             missingStrings[key] = text;
73333             var missing = key + ': ' + text;
73334             if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
73335           }
73336         }
73337
73338         function localize(obj) {
73339           var key; // Assign name if entity has one..
73340
73341           var name = obj.tags && obj.tags.name;
73342
73343           if (name) {
73344             key = 'intro.graph.name.' + slugify(name);
73345             obj.tags.name = _t(key, {
73346               "default": name
73347             });
73348             checkKey(key, name);
73349           } // Assign street name if entity has one..
73350
73351
73352           var street = obj.tags && obj.tags['addr:street'];
73353
73354           if (street) {
73355             key = 'intro.graph.name.' + slugify(street);
73356             obj.tags['addr:street'] = _t(key, {
73357               "default": street
73358             });
73359             checkKey(key, street); // Add address details common across walkthrough..
73360
73361             var addrTags = ['block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood', 'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'];
73362             addrTags.forEach(function (k) {
73363               var key = 'intro.graph.' + k;
73364               var tag = 'addr:' + k;
73365               var val = obj.tags && obj.tags[tag];
73366               var str = _t(key, {
73367                 "default": val
73368               });
73369
73370               if (str) {
73371                 if (str.match(/^<.*>$/) !== null) {
73372                   delete obj.tags[tag];
73373                 } else {
73374                   obj.tags[tag] = str;
73375                 }
73376               }
73377             });
73378           }
73379
73380           return obj;
73381         } // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
73382
73383         function isMostlySquare(points) {
73384           // note: uses 15 here instead of the 12 from actionOrthogonalize because
73385           // actionOrthogonalize can actually straighten some larger angles as it iterates
73386           var threshold = 15; // degrees within right or straight
73387
73388           var lowerBound = Math.cos((90 - threshold) * Math.PI / 180); // near right
73389
73390           var upperBound = Math.cos(threshold * Math.PI / 180); // near straight
73391
73392           for (var i = 0; i < points.length; i++) {
73393             var a = points[(i - 1 + points.length) % points.length];
73394             var origin = points[i];
73395             var b = points[(i + 1) % points.length];
73396             var dotp = geoVecNormalizedDot(a, b, origin);
73397             var mag = Math.abs(dotp);
73398
73399             if (mag > lowerBound && mag < upperBound) {
73400               return false;
73401             }
73402           }
73403
73404           return true;
73405         }
73406         function selectMenuItem(context, operation) {
73407           return context.container().select('.edit-menu .edit-menu-item-' + operation);
73408         }
73409         function transitionTime(point1, point2) {
73410           var distance = geoSphericalDistance(point1, point2);
73411
73412           if (distance === 0) {
73413             return 0;
73414           } else if (distance < 80) {
73415             return 500;
73416           } else {
73417             return 1000;
73418           }
73419         }
73420
73421         // hide class, which sets display=none, and a d3 transition for opacity.
73422         // this will cause blinking when called repeatedly, so check that the
73423         // value actually changes between calls.
73424
73425         function uiToggle(show, callback) {
73426           return function (selection) {
73427             selection.style('opacity', show ? 0 : 1).classed('hide', false).transition().style('opacity', show ? 1 : 0).on('end', function () {
73428               select(this).classed('hide', !show).style('opacity', null);
73429               if (callback) callback.apply(this);
73430             });
73431           };
73432         }
73433
73434         function uiCurtain(containerNode) {
73435           var surface = select(null),
73436               tooltip = select(null),
73437               darkness = select(null);
73438
73439           function curtain(selection) {
73440             surface = selection.append('svg').attr('class', 'curtain').style('top', 0).style('left', 0);
73441             darkness = surface.append('path').attr('x', 0).attr('y', 0).attr('class', 'curtain-darkness');
73442             select(window).on('resize.curtain', resize);
73443             tooltip = selection.append('div').attr('class', 'tooltip');
73444             tooltip.append('div').attr('class', 'popover-arrow');
73445             tooltip.append('div').attr('class', 'popover-inner');
73446             resize();
73447
73448             function resize() {
73449               surface.attr('width', containerNode.clientWidth).attr('height', containerNode.clientHeight);
73450               curtain.cut(darkness.datum());
73451             }
73452           }
73453           /**
73454            * Reveal cuts the curtain to highlight the given box,
73455            * and shows a tooltip with instructions next to the box.
73456            *
73457            * @param  {String|ClientRect} [box]   box used to cut the curtain
73458            * @param  {String}    [text]          text for a tooltip
73459            * @param  {Object}    [options]
73460            * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
73461            * @param  {integer}   [options.duration]        transition time in milliseconds
73462            * @param  {string}    [options.buttonText]      if set, create a button with this text label
73463            * @param  {function}  [options.buttonCallback]  if set, the callback for the button
73464            * @param  {function}  [options.padding]         extra margin in px to put around bbox
73465            * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
73466            */
73467
73468
73469           curtain.reveal = function (box, html, options) {
73470             options = options || {};
73471
73472             if (typeof box === 'string') {
73473               box = select(box).node();
73474             }
73475
73476             if (box && box.getBoundingClientRect) {
73477               box = copyBox(box.getBoundingClientRect());
73478               var containerRect = containerNode.getBoundingClientRect();
73479               box.top -= containerRect.top;
73480               box.left -= containerRect.left;
73481             }
73482
73483             if (box && options.padding) {
73484               box.top -= options.padding;
73485               box.left -= options.padding;
73486               box.bottom += options.padding;
73487               box.right += options.padding;
73488               box.height += options.padding * 2;
73489               box.width += options.padding * 2;
73490             }
73491
73492             var tooltipBox;
73493
73494             if (options.tooltipBox) {
73495               tooltipBox = options.tooltipBox;
73496
73497               if (typeof tooltipBox === 'string') {
73498                 tooltipBox = select(tooltipBox).node();
73499               }
73500
73501               if (tooltipBox && tooltipBox.getBoundingClientRect) {
73502                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
73503               }
73504             } else {
73505               tooltipBox = box;
73506             }
73507
73508             if (tooltipBox && html) {
73509               if (html.indexOf('**') !== -1) {
73510                 if (html.indexOf('<span') === 0) {
73511                   html = html.replace(/^(<span.*?>)(.+?)(\*\*)/, '$1<span>$2</span>$3');
73512                 } else {
73513                   html = html.replace(/^(.+?)(\*\*)/, '<span>$1</span>$2');
73514                 } // pseudo markdown bold text for the instruction section..
73515
73516
73517                 html = html.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
73518               }
73519
73520               html = html.replace(/\*(.*?)\*/g, '<em>$1</em>'); // emphasis
73521
73522               html = html.replace(/\{br\}/g, '<br/><br/>'); // linebreak
73523
73524               if (options.buttonText && options.buttonCallback) {
73525                 html += '<div class="button-section">' + '<button href="#" class="button action">' + options.buttonText + '</button></div>';
73526               }
73527
73528               var classes = 'curtain-tooltip popover tooltip arrowed in ' + (options.tooltipClass || '');
73529               tooltip.classed(classes, true).selectAll('.popover-inner').html(html);
73530
73531               if (options.buttonText && options.buttonCallback) {
73532                 var button = tooltip.selectAll('.button-section .button.action');
73533                 button.on('click', function (d3_event) {
73534                   d3_event.preventDefault();
73535                   options.buttonCallback();
73536                 });
73537               }
73538
73539               var tip = copyBox(tooltip.node().getBoundingClientRect()),
73540                   w = containerNode.clientWidth,
73541                   h = containerNode.clientHeight,
73542                   tooltipWidth = 200,
73543                   tooltipArrow = 5,
73544                   side,
73545                   pos; // hack: this will have bottom placement,
73546               // so need to reserve extra space for the tooltip illustration.
73547
73548               if (options.tooltipClass === 'intro-mouse') {
73549                 tip.height += 80;
73550               } // trim box dimensions to just the portion that fits in the container..
73551
73552
73553               if (tooltipBox.top + tooltipBox.height > h) {
73554                 tooltipBox.height -= tooltipBox.top + tooltipBox.height - h;
73555               }
73556
73557               if (tooltipBox.left + tooltipBox.width > w) {
73558                 tooltipBox.width -= tooltipBox.left + tooltipBox.width - w;
73559               } // determine tooltip placement..
73560
73561
73562               if (tooltipBox.top + tooltipBox.height < 100) {
73563                 // tooltip below box..
73564                 side = 'bottom';
73565                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top + tooltipBox.height];
73566               } else if (tooltipBox.top > h - 140) {
73567                 // tooltip above box..
73568                 side = 'top';
73569                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top - tip.height];
73570               } else {
73571                 // tooltip to the side of the tooltipBox..
73572                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
73573
73574                 if (_mainLocalizer.textDirection() === 'rtl') {
73575                   if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
73576                     side = 'right';
73577                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
73578                   } else {
73579                     side = 'left';
73580                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
73581                   }
73582                 } else {
73583                   if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
73584                     side = 'left';
73585                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
73586                   } else {
73587                     side = 'right';
73588                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
73589                   }
73590                 }
73591               }
73592
73593               if (options.duration !== 0 || !tooltip.classed(side)) {
73594                 tooltip.call(uiToggle(true));
73595               }
73596
73597               tooltip.style('top', pos[1] + 'px').style('left', pos[0] + 'px').attr('class', classes + ' ' + side); // shift popover-inner if it is very close to the top or bottom edge
73598               // (doesn't affect the placement of the popover-arrow)
73599
73600               var shiftY = 0;
73601
73602               if (side === 'left' || side === 'right') {
73603                 if (pos[1] < 60) {
73604                   shiftY = 60 - pos[1];
73605                 } else if (pos[1] + tip.height > h - 100) {
73606                   shiftY = h - pos[1] - tip.height - 100;
73607                 }
73608               }
73609
73610               tooltip.selectAll('.popover-inner').style('top', shiftY + 'px');
73611             } else {
73612               tooltip.classed('in', false).call(uiToggle(false));
73613             }
73614
73615             curtain.cut(box, options.duration);
73616             return tooltip;
73617           };
73618
73619           curtain.cut = function (datum, duration) {
73620             darkness.datum(datum).interrupt();
73621             var selection;
73622
73623             if (duration === 0) {
73624               selection = darkness;
73625             } else {
73626               selection = darkness.transition().duration(duration || 600).ease(linear$1);
73627             }
73628
73629             selection.attr('d', function (d) {
73630               var containerWidth = containerNode.clientWidth;
73631               var containerHeight = containerNode.clientHeight;
73632               var string = 'M 0,0 L 0,' + containerHeight + ' L ' + containerWidth + ',' + containerHeight + 'L' + containerWidth + ',0 Z';
73633               if (!d) return string;
73634               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';
73635             });
73636           };
73637
73638           curtain.remove = function () {
73639             surface.remove();
73640             tooltip.remove();
73641             select(window).on('resize.curtain', null);
73642           }; // ClientRects are immutable, so copy them to an object,
73643           // in case we need to trim the height/width.
73644
73645
73646           function copyBox(src) {
73647             return {
73648               top: src.top,
73649               right: src.right,
73650               bottom: src.bottom,
73651               left: src.left,
73652               width: src.width,
73653               height: src.height
73654             };
73655           }
73656
73657           return curtain;
73658         }
73659
73660         function uiIntroWelcome(context, reveal) {
73661           var dispatch = dispatch$8('done');
73662           var chapter = {
73663             title: 'intro.welcome.title'
73664           };
73665
73666           function welcome() {
73667             context.map().centerZoom([-85.63591, 41.94285], 19);
73668             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.welcome'), {
73669               buttonText: _t.html('intro.ok'),
73670               buttonCallback: practice
73671             });
73672           }
73673
73674           function practice() {
73675             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.practice'), {
73676               buttonText: _t.html('intro.ok'),
73677               buttonCallback: words
73678             });
73679           }
73680
73681           function words() {
73682             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.words'), {
73683               buttonText: _t.html('intro.ok'),
73684               buttonCallback: chapters
73685             });
73686           }
73687
73688           function chapters() {
73689             dispatch.call('done');
73690             reveal('.intro-nav-wrap .chapter-navigation', helpHtml('intro.welcome.chapters', {
73691               next: _t('intro.navigation.title')
73692             }));
73693           }
73694
73695           chapter.enter = function () {
73696             welcome();
73697           };
73698
73699           chapter.exit = function () {
73700             context.container().select('.curtain-tooltip.intro-mouse').selectAll('.counter').remove();
73701           };
73702
73703           chapter.restart = function () {
73704             chapter.exit();
73705             chapter.enter();
73706           };
73707
73708           return utilRebind(chapter, dispatch, 'on');
73709         }
73710
73711         function uiIntroNavigation(context, reveal) {
73712           var dispatch = dispatch$8('done');
73713           var timeouts = [];
73714           var hallId = 'n2061';
73715           var townHall = [-85.63591, 41.94285];
73716           var springStreetId = 'w397';
73717           var springStreetEndId = 'n1834';
73718           var springStreet = [-85.63582, 41.94255];
73719           var onewayField = _mainPresetIndex.field('oneway');
73720           var maxspeedField = _mainPresetIndex.field('maxspeed');
73721           var chapter = {
73722             title: 'intro.navigation.title'
73723           };
73724
73725           function timeout(f, t) {
73726             timeouts.push(window.setTimeout(f, t));
73727           }
73728
73729           function eventCancel(d3_event) {
73730             d3_event.stopPropagation();
73731             d3_event.preventDefault();
73732           }
73733
73734           function isTownHallSelected() {
73735             var ids = context.selectedIDs();
73736             return ids.length === 1 && ids[0] === hallId;
73737           }
73738
73739           function dragMap() {
73740             context.enter(modeBrowse(context));
73741             context.history().reset('initial');
73742             var msec = transitionTime(townHall, context.map().center());
73743
73744             if (msec) {
73745               reveal(null, null, {
73746                 duration: 0
73747               });
73748             }
73749
73750             context.map().centerZoomEase(townHall, 19, msec);
73751             timeout(function () {
73752               var centerStart = context.map().center();
73753               var textId = context.lastPointerType() === 'mouse' ? 'drag' : 'drag_touch';
73754               var dragString = helpHtml('intro.navigation.map_info') + '{br}' + helpHtml('intro.navigation.' + textId);
73755               reveal('.surface', dragString);
73756               context.map().on('drawn.intro', function () {
73757                 reveal('.surface', dragString, {
73758                   duration: 0
73759                 });
73760               });
73761               context.map().on('move.intro', function () {
73762                 var centerNow = context.map().center();
73763
73764                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
73765                   context.map().on('move.intro', null);
73766                   timeout(function () {
73767                     continueTo(zoomMap);
73768                   }, 3000);
73769                 }
73770               });
73771             }, msec + 100);
73772
73773             function continueTo(nextStep) {
73774               context.map().on('move.intro drawn.intro', null);
73775               nextStep();
73776             }
73777           }
73778
73779           function zoomMap() {
73780             var zoomStart = context.map().zoom();
73781             var textId = context.lastPointerType() === 'mouse' ? 'zoom' : 'zoom_touch';
73782             var zoomString = helpHtml('intro.navigation.' + textId);
73783             reveal('.surface', zoomString);
73784             context.map().on('drawn.intro', function () {
73785               reveal('.surface', zoomString, {
73786                 duration: 0
73787               });
73788             });
73789             context.map().on('move.intro', function () {
73790               if (context.map().zoom() !== zoomStart) {
73791                 context.map().on('move.intro', null);
73792                 timeout(function () {
73793                   continueTo(features);
73794                 }, 3000);
73795               }
73796             });
73797
73798             function continueTo(nextStep) {
73799               context.map().on('move.intro drawn.intro', null);
73800               nextStep();
73801             }
73802           }
73803
73804           function features() {
73805             var onClick = function onClick() {
73806               continueTo(pointsLinesAreas);
73807             };
73808
73809             reveal('.surface', helpHtml('intro.navigation.features'), {
73810               buttonText: _t.html('intro.ok'),
73811               buttonCallback: onClick
73812             });
73813             context.map().on('drawn.intro', function () {
73814               reveal('.surface', helpHtml('intro.navigation.features'), {
73815                 duration: 0,
73816                 buttonText: _t.html('intro.ok'),
73817                 buttonCallback: onClick
73818               });
73819             });
73820
73821             function continueTo(nextStep) {
73822               context.map().on('drawn.intro', null);
73823               nextStep();
73824             }
73825           }
73826
73827           function pointsLinesAreas() {
73828             var onClick = function onClick() {
73829               continueTo(nodesWays);
73830             };
73831
73832             reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
73833               buttonText: _t.html('intro.ok'),
73834               buttonCallback: onClick
73835             });
73836             context.map().on('drawn.intro', function () {
73837               reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
73838                 duration: 0,
73839                 buttonText: _t.html('intro.ok'),
73840                 buttonCallback: onClick
73841               });
73842             });
73843
73844             function continueTo(nextStep) {
73845               context.map().on('drawn.intro', null);
73846               nextStep();
73847             }
73848           }
73849
73850           function nodesWays() {
73851             var onClick = function onClick() {
73852               continueTo(clickTownHall);
73853             };
73854
73855             reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
73856               buttonText: _t.html('intro.ok'),
73857               buttonCallback: onClick
73858             });
73859             context.map().on('drawn.intro', function () {
73860               reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
73861                 duration: 0,
73862                 buttonText: _t.html('intro.ok'),
73863                 buttonCallback: onClick
73864               });
73865             });
73866
73867             function continueTo(nextStep) {
73868               context.map().on('drawn.intro', null);
73869               nextStep();
73870             }
73871           }
73872
73873           function clickTownHall() {
73874             context.enter(modeBrowse(context));
73875             context.history().reset('initial');
73876             var entity = context.hasEntity(hallId);
73877             if (!entity) return;
73878             reveal(null, null, {
73879               duration: 0
73880             });
73881             context.map().centerZoomEase(entity.loc, 19, 500);
73882             timeout(function () {
73883               var entity = context.hasEntity(hallId);
73884               if (!entity) return;
73885               var box = pointBox(entity.loc, context);
73886               var textId = context.lastPointerType() === 'mouse' ? 'click_townhall' : 'tap_townhall';
73887               reveal(box, helpHtml('intro.navigation.' + textId));
73888               context.map().on('move.intro drawn.intro', function () {
73889                 var entity = context.hasEntity(hallId);
73890                 if (!entity) return;
73891                 var box = pointBox(entity.loc, context);
73892                 reveal(box, helpHtml('intro.navigation.' + textId), {
73893                   duration: 0
73894                 });
73895               });
73896               context.on('enter.intro', function () {
73897                 if (isTownHallSelected()) continueTo(selectedTownHall);
73898               });
73899             }, 550); // after centerZoomEase
73900
73901             context.history().on('change.intro', function () {
73902               if (!context.hasEntity(hallId)) {
73903                 continueTo(clickTownHall);
73904               }
73905             });
73906
73907             function continueTo(nextStep) {
73908               context.on('enter.intro', null);
73909               context.map().on('move.intro drawn.intro', null);
73910               context.history().on('change.intro', null);
73911               nextStep();
73912             }
73913           }
73914
73915           function selectedTownHall() {
73916             if (!isTownHallSelected()) return clickTownHall();
73917             var entity = context.hasEntity(hallId);
73918             if (!entity) return clickTownHall();
73919             var box = pointBox(entity.loc, context);
73920
73921             var onClick = function onClick() {
73922               continueTo(editorTownHall);
73923             };
73924
73925             reveal(box, helpHtml('intro.navigation.selected_townhall'), {
73926               buttonText: _t.html('intro.ok'),
73927               buttonCallback: onClick
73928             });
73929             context.map().on('move.intro drawn.intro', function () {
73930               var entity = context.hasEntity(hallId);
73931               if (!entity) return;
73932               var box = pointBox(entity.loc, context);
73933               reveal(box, helpHtml('intro.navigation.selected_townhall'), {
73934                 duration: 0,
73935                 buttonText: _t.html('intro.ok'),
73936                 buttonCallback: onClick
73937               });
73938             });
73939             context.history().on('change.intro', function () {
73940               if (!context.hasEntity(hallId)) {
73941                 continueTo(clickTownHall);
73942               }
73943             });
73944
73945             function continueTo(nextStep) {
73946               context.map().on('move.intro drawn.intro', null);
73947               context.history().on('change.intro', null);
73948               nextStep();
73949             }
73950           }
73951
73952           function editorTownHall() {
73953             if (!isTownHallSelected()) return clickTownHall(); // disallow scrolling
73954
73955             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73956
73957             var onClick = function onClick() {
73958               continueTo(presetTownHall);
73959             };
73960
73961             reveal('.entity-editor-pane', helpHtml('intro.navigation.editor_townhall'), {
73962               buttonText: _t.html('intro.ok'),
73963               buttonCallback: onClick
73964             });
73965             context.on('exit.intro', function () {
73966               continueTo(clickTownHall);
73967             });
73968             context.history().on('change.intro', function () {
73969               if (!context.hasEntity(hallId)) {
73970                 continueTo(clickTownHall);
73971               }
73972             });
73973
73974             function continueTo(nextStep) {
73975               context.on('exit.intro', null);
73976               context.history().on('change.intro', null);
73977               context.container().select('.inspector-wrap').on('wheel.intro', null);
73978               nextStep();
73979             }
73980           }
73981
73982           function presetTownHall() {
73983             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
73984
73985             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
73986
73987             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel); // preset match, in case the user happened to change it.
73988
73989             var entity = context.entity(context.selectedIDs()[0]);
73990             var preset = _mainPresetIndex.match(entity, context.graph());
73991
73992             var onClick = function onClick() {
73993               continueTo(fieldsTownHall);
73994             };
73995
73996             reveal('.entity-editor-pane .section-feature-type', helpHtml('intro.navigation.preset_townhall', {
73997               preset: preset.name()
73998             }), {
73999               buttonText: _t.html('intro.ok'),
74000               buttonCallback: onClick
74001             });
74002             context.on('exit.intro', function () {
74003               continueTo(clickTownHall);
74004             });
74005             context.history().on('change.intro', function () {
74006               if (!context.hasEntity(hallId)) {
74007                 continueTo(clickTownHall);
74008               }
74009             });
74010
74011             function continueTo(nextStep) {
74012               context.on('exit.intro', null);
74013               context.history().on('change.intro', null);
74014               context.container().select('.inspector-wrap').on('wheel.intro', null);
74015               nextStep();
74016             }
74017           }
74018
74019           function fieldsTownHall() {
74020             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
74021
74022             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
74023
74024             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74025
74026             var onClick = function onClick() {
74027               continueTo(closeTownHall);
74028             };
74029
74030             reveal('.entity-editor-pane .section-preset-fields', helpHtml('intro.navigation.fields_townhall'), {
74031               buttonText: _t.html('intro.ok'),
74032               buttonCallback: onClick
74033             });
74034             context.on('exit.intro', function () {
74035               continueTo(clickTownHall);
74036             });
74037             context.history().on('change.intro', function () {
74038               if (!context.hasEntity(hallId)) {
74039                 continueTo(clickTownHall);
74040               }
74041             });
74042
74043             function continueTo(nextStep) {
74044               context.on('exit.intro', null);
74045               context.history().on('change.intro', null);
74046               context.container().select('.inspector-wrap').on('wheel.intro', null);
74047               nextStep();
74048             }
74049           }
74050
74051           function closeTownHall() {
74052             if (!isTownHallSelected()) return clickTownHall();
74053             var selector = '.entity-editor-pane button.close svg use';
74054             var href = select(selector).attr('href') || '#iD-icon-close';
74055             reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
74056               button: icon(href, 'inline')
74057             }));
74058             context.on('exit.intro', function () {
74059               continueTo(searchStreet);
74060             });
74061             context.history().on('change.intro', function () {
74062               // update the close icon in the tooltip if the user edits something.
74063               var selector = '.entity-editor-pane button.close svg use';
74064               var href = select(selector).attr('href') || '#iD-icon-close';
74065               reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
74066                 button: icon(href, 'inline')
74067               }), {
74068                 duration: 0
74069               });
74070             });
74071
74072             function continueTo(nextStep) {
74073               context.on('exit.intro', null);
74074               context.history().on('change.intro', null);
74075               nextStep();
74076             }
74077           }
74078
74079           function searchStreet() {
74080             context.enter(modeBrowse(context));
74081             context.history().reset('initial'); // ensure spring street exists
74082
74083             var msec = transitionTime(springStreet, context.map().center());
74084
74085             if (msec) {
74086               reveal(null, null, {
74087                 duration: 0
74088               });
74089             }
74090
74091             context.map().centerZoomEase(springStreet, 19, msec); // ..and user can see it
74092
74093             timeout(function () {
74094               reveal('.search-header input', helpHtml('intro.navigation.search_street', {
74095                 name: _t('intro.graph.name.spring-street')
74096               }));
74097               context.container().select('.search-header input').on('keyup.intro', checkSearchResult);
74098             }, msec + 100);
74099           }
74100
74101           function checkSearchResult() {
74102             var first = context.container().select('.feature-list-item:nth-child(0n+2)'); // skip "No Results" item
74103
74104             var firstName = first.select('.entity-name');
74105             var name = _t('intro.graph.name.spring-street');
74106
74107             if (!firstName.empty() && firstName.html() === name) {
74108               reveal(first.node(), helpHtml('intro.navigation.choose_street', {
74109                 name: name
74110               }), {
74111                 duration: 300
74112               });
74113               context.on('exit.intro', function () {
74114                 continueTo(selectedStreet);
74115               });
74116               context.container().select('.search-header input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
74117             }
74118
74119             function continueTo(nextStep) {
74120               context.on('exit.intro', null);
74121               context.container().select('.search-header input').on('keydown.intro', null).on('keyup.intro', null);
74122               nextStep();
74123             }
74124           }
74125
74126           function selectedStreet() {
74127             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
74128               return searchStreet();
74129             }
74130
74131             var onClick = function onClick() {
74132               continueTo(editorStreet);
74133             };
74134
74135             var entity = context.entity(springStreetEndId);
74136             var box = pointBox(entity.loc, context);
74137             box.height = 500;
74138             reveal(box, helpHtml('intro.navigation.selected_street', {
74139               name: _t('intro.graph.name.spring-street')
74140             }), {
74141               duration: 600,
74142               buttonText: _t.html('intro.ok'),
74143               buttonCallback: onClick
74144             });
74145             timeout(function () {
74146               context.map().on('move.intro drawn.intro', function () {
74147                 var entity = context.hasEntity(springStreetEndId);
74148                 if (!entity) return;
74149                 var box = pointBox(entity.loc, context);
74150                 box.height = 500;
74151                 reveal(box, helpHtml('intro.navigation.selected_street', {
74152                   name: _t('intro.graph.name.spring-street')
74153                 }), {
74154                   duration: 0,
74155                   buttonText: _t.html('intro.ok'),
74156                   buttonCallback: onClick
74157                 });
74158               });
74159             }, 600); // after reveal.
74160
74161             context.on('enter.intro', function (mode) {
74162               if (!context.hasEntity(springStreetId)) {
74163                 return continueTo(searchStreet);
74164               }
74165
74166               var ids = context.selectedIDs();
74167
74168               if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
74169                 // keep Spring Street selected..
74170                 context.enter(modeSelect(context, [springStreetId]));
74171               }
74172             });
74173             context.history().on('change.intro', function () {
74174               if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
74175                 timeout(function () {
74176                   continueTo(searchStreet);
74177                 }, 300); // after any transition (e.g. if user deleted intersection)
74178               }
74179             });
74180
74181             function continueTo(nextStep) {
74182               context.map().on('move.intro drawn.intro', null);
74183               context.on('enter.intro', null);
74184               context.history().on('change.intro', null);
74185               nextStep();
74186             }
74187           }
74188
74189           function editorStreet() {
74190             var selector = '.entity-editor-pane button.close svg use';
74191             var href = select(selector).attr('href') || '#iD-icon-close';
74192             reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
74193               button: icon(href, 'inline'),
74194               field1: onewayField.label(),
74195               field2: maxspeedField.label()
74196             }));
74197             context.on('exit.intro', function () {
74198               continueTo(play);
74199             });
74200             context.history().on('change.intro', function () {
74201               // update the close icon in the tooltip if the user edits something.
74202               var selector = '.entity-editor-pane button.close svg use';
74203               var href = select(selector).attr('href') || '#iD-icon-close';
74204               reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
74205                 button: icon(href, 'inline'),
74206                 field1: onewayField.label(),
74207                 field2: maxspeedField.label()
74208               }), {
74209                 duration: 0
74210               });
74211             });
74212
74213             function continueTo(nextStep) {
74214               context.on('exit.intro', null);
74215               context.history().on('change.intro', null);
74216               nextStep();
74217             }
74218           }
74219
74220           function play() {
74221             dispatch.call('done');
74222             reveal('.ideditor', helpHtml('intro.navigation.play', {
74223               next: _t('intro.points.title')
74224             }), {
74225               tooltipBox: '.intro-nav-wrap .chapter-point',
74226               buttonText: _t.html('intro.ok'),
74227               buttonCallback: function buttonCallback() {
74228                 reveal('.ideditor');
74229               }
74230             });
74231           }
74232
74233           chapter.enter = function () {
74234             dragMap();
74235           };
74236
74237           chapter.exit = function () {
74238             timeouts.forEach(window.clearTimeout);
74239             context.on('enter.intro exit.intro', null);
74240             context.map().on('move.intro drawn.intro', null);
74241             context.history().on('change.intro', null);
74242             context.container().select('.inspector-wrap').on('wheel.intro', null);
74243             context.container().select('.search-header input').on('keydown.intro keyup.intro', null);
74244           };
74245
74246           chapter.restart = function () {
74247             chapter.exit();
74248             chapter.enter();
74249           };
74250
74251           return utilRebind(chapter, dispatch, 'on');
74252         }
74253
74254         function uiIntroPoint(context, reveal) {
74255           var dispatch = dispatch$8('done');
74256           var timeouts = [];
74257           var intersection = [-85.63279, 41.94394];
74258           var building = [-85.632422, 41.944045];
74259           var cafePreset = _mainPresetIndex.item('amenity/cafe');
74260           var _pointID = null;
74261           var chapter = {
74262             title: 'intro.points.title'
74263           };
74264
74265           function timeout(f, t) {
74266             timeouts.push(window.setTimeout(f, t));
74267           }
74268
74269           function eventCancel(d3_event) {
74270             d3_event.stopPropagation();
74271             d3_event.preventDefault();
74272           }
74273
74274           function addPoint() {
74275             context.enter(modeBrowse(context));
74276             context.history().reset('initial');
74277             var msec = transitionTime(intersection, context.map().center());
74278
74279             if (msec) {
74280               reveal(null, null, {
74281                 duration: 0
74282               });
74283             }
74284
74285             context.map().centerZoomEase(intersection, 19, msec);
74286             timeout(function () {
74287               var tooltip = reveal('button.add-point', helpHtml('intro.points.points_info') + '{br}' + helpHtml('intro.points.add_point'));
74288               _pointID = null;
74289               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-points');
74290               context.on('enter.intro', function (mode) {
74291                 if (mode.id !== 'add-point') return;
74292                 continueTo(placePoint);
74293               });
74294             }, msec + 100);
74295
74296             function continueTo(nextStep) {
74297               context.on('enter.intro', null);
74298               nextStep();
74299             }
74300           }
74301
74302           function placePoint() {
74303             if (context.mode().id !== 'add-point') {
74304               return chapter.restart();
74305             }
74306
74307             var pointBox = pad(building, 150, context);
74308             var textId = context.lastPointerType() === 'mouse' ? 'place_point' : 'place_point_touch';
74309             reveal(pointBox, helpHtml('intro.points.' + textId));
74310             context.map().on('move.intro drawn.intro', function () {
74311               pointBox = pad(building, 150, context);
74312               reveal(pointBox, helpHtml('intro.points.' + textId), {
74313                 duration: 0
74314               });
74315             });
74316             context.on('enter.intro', function (mode) {
74317               if (mode.id !== 'select') return chapter.restart();
74318               _pointID = context.mode().selectedIDs()[0];
74319               continueTo(searchPreset);
74320             });
74321
74322             function continueTo(nextStep) {
74323               context.map().on('move.intro drawn.intro', null);
74324               context.on('enter.intro', null);
74325               nextStep();
74326             }
74327           }
74328
74329           function searchPreset() {
74330             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
74331               return addPoint();
74332             } // disallow scrolling
74333
74334
74335             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74336             context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
74337             reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
74338               preset: cafePreset.name()
74339             }));
74340             context.on('enter.intro', function (mode) {
74341               if (!_pointID || !context.hasEntity(_pointID)) {
74342                 return continueTo(addPoint);
74343               }
74344
74345               var ids = context.selectedIDs();
74346
74347               if (mode.id !== 'select' || !ids.length || ids[0] !== _pointID) {
74348                 // keep the user's point selected..
74349                 context.enter(modeSelect(context, [_pointID])); // disallow scrolling
74350
74351                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74352                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
74353                 reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
74354                   preset: cafePreset.name()
74355                 }));
74356                 context.history().on('change.intro', null);
74357               }
74358             });
74359
74360             function checkPresetSearch() {
74361               var first = context.container().select('.preset-list-item:first-child');
74362
74363               if (first.classed('preset-amenity-cafe')) {
74364                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
74365                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.points.choose_cafe', {
74366                   preset: cafePreset.name()
74367                 }), {
74368                   duration: 300
74369                 });
74370                 context.history().on('change.intro', function () {
74371                   continueTo(aboutFeatureEditor);
74372                 });
74373               }
74374             }
74375
74376             function continueTo(nextStep) {
74377               context.on('enter.intro', null);
74378               context.history().on('change.intro', null);
74379               context.container().select('.inspector-wrap').on('wheel.intro', null);
74380               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
74381               nextStep();
74382             }
74383           }
74384
74385           function aboutFeatureEditor() {
74386             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
74387               return addPoint();
74388             }
74389
74390             timeout(function () {
74391               reveal('.entity-editor-pane', helpHtml('intro.points.feature_editor'), {
74392                 tooltipClass: 'intro-points-describe',
74393                 buttonText: _t.html('intro.ok'),
74394                 buttonCallback: function buttonCallback() {
74395                   continueTo(addName);
74396                 }
74397               });
74398             }, 400);
74399             context.on('exit.intro', function () {
74400               // if user leaves select mode here, just continue with the tutorial.
74401               continueTo(reselectPoint);
74402             });
74403
74404             function continueTo(nextStep) {
74405               context.on('exit.intro', null);
74406               nextStep();
74407             }
74408           }
74409
74410           function addName() {
74411             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
74412               return addPoint();
74413             } // reset pane, in case user happened to change it..
74414
74415
74416             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
74417             var addNameString = helpHtml('intro.points.fields_info') + '{br}' + helpHtml('intro.points.add_name');
74418             timeout(function () {
74419               // It's possible for the user to add a name in a previous step..
74420               // If so, don't tell them to add the name in this step.
74421               // Give them an OK button instead.
74422               var entity = context.entity(_pointID);
74423
74424               if (entity.tags.name) {
74425                 var tooltip = reveal('.entity-editor-pane', addNameString, {
74426                   tooltipClass: 'intro-points-describe',
74427                   buttonText: _t.html('intro.ok'),
74428                   buttonCallback: function buttonCallback() {
74429                     continueTo(addCloseEditor);
74430                   }
74431                 });
74432                 tooltip.select('.instruction').style('display', 'none');
74433               } else {
74434                 reveal('.entity-editor-pane', addNameString, {
74435                   tooltipClass: 'intro-points-describe'
74436                 });
74437               }
74438             }, 400);
74439             context.history().on('change.intro', function () {
74440               continueTo(addCloseEditor);
74441             });
74442             context.on('exit.intro', function () {
74443               // if user leaves select mode here, just continue with the tutorial.
74444               continueTo(reselectPoint);
74445             });
74446
74447             function continueTo(nextStep) {
74448               context.on('exit.intro', null);
74449               context.history().on('change.intro', null);
74450               nextStep();
74451             }
74452           }
74453
74454           function addCloseEditor() {
74455             // reset pane, in case user happened to change it..
74456             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
74457             var selector = '.entity-editor-pane button.close svg use';
74458             var href = select(selector).attr('href') || '#iD-icon-close';
74459             context.on('exit.intro', function () {
74460               continueTo(reselectPoint);
74461             });
74462             reveal('.entity-editor-pane', helpHtml('intro.points.add_close', {
74463               button: icon(href, 'inline')
74464             }));
74465
74466             function continueTo(nextStep) {
74467               context.on('exit.intro', null);
74468               nextStep();
74469             }
74470           }
74471
74472           function reselectPoint() {
74473             if (!_pointID) return chapter.restart();
74474             var entity = context.hasEntity(_pointID);
74475             if (!entity) return chapter.restart(); // make sure it's still a cafe, in case user somehow changed it..
74476
74477             var oldPreset = _mainPresetIndex.match(entity, context.graph());
74478             context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
74479             context.enter(modeBrowse(context));
74480             var msec = transitionTime(entity.loc, context.map().center());
74481
74482             if (msec) {
74483               reveal(null, null, {
74484                 duration: 0
74485               });
74486             }
74487
74488             context.map().centerEase(entity.loc, msec);
74489             timeout(function () {
74490               var box = pointBox(entity.loc, context);
74491               reveal(box, helpHtml('intro.points.reselect'), {
74492                 duration: 600
74493               });
74494               timeout(function () {
74495                 context.map().on('move.intro drawn.intro', function () {
74496                   var entity = context.hasEntity(_pointID);
74497                   if (!entity) return chapter.restart();
74498                   var box = pointBox(entity.loc, context);
74499                   reveal(box, helpHtml('intro.points.reselect'), {
74500                     duration: 0
74501                   });
74502                 });
74503               }, 600); // after reveal..
74504
74505               context.on('enter.intro', function (mode) {
74506                 if (mode.id !== 'select') return;
74507                 continueTo(updatePoint);
74508               });
74509             }, msec + 100);
74510
74511             function continueTo(nextStep) {
74512               context.map().on('move.intro drawn.intro', null);
74513               context.on('enter.intro', null);
74514               nextStep();
74515             }
74516           }
74517
74518           function updatePoint() {
74519             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
74520               return continueTo(reselectPoint);
74521             } // reset pane, in case user happened to untag the point..
74522
74523
74524             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
74525             context.on('exit.intro', function () {
74526               continueTo(reselectPoint);
74527             });
74528             context.history().on('change.intro', function () {
74529               continueTo(updateCloseEditor);
74530             });
74531             timeout(function () {
74532               reveal('.entity-editor-pane', helpHtml('intro.points.update'), {
74533                 tooltipClass: 'intro-points-describe'
74534               });
74535             }, 400);
74536
74537             function continueTo(nextStep) {
74538               context.on('exit.intro', null);
74539               context.history().on('change.intro', null);
74540               nextStep();
74541             }
74542           }
74543
74544           function updateCloseEditor() {
74545             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
74546               return continueTo(reselectPoint);
74547             } // reset pane, in case user happened to change it..
74548
74549
74550             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
74551             context.on('exit.intro', function () {
74552               continueTo(rightClickPoint);
74553             });
74554             timeout(function () {
74555               reveal('.entity-editor-pane', helpHtml('intro.points.update_close', {
74556                 button: icon('#iD-icon-close', 'inline')
74557               }));
74558             }, 500);
74559
74560             function continueTo(nextStep) {
74561               context.on('exit.intro', null);
74562               nextStep();
74563             }
74564           }
74565
74566           function rightClickPoint() {
74567             if (!_pointID) return chapter.restart();
74568             var entity = context.hasEntity(_pointID);
74569             if (!entity) return chapter.restart();
74570             context.enter(modeBrowse(context));
74571             var box = pointBox(entity.loc, context);
74572             var textId = context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch';
74573             reveal(box, helpHtml('intro.points.' + textId), {
74574               duration: 600
74575             });
74576             timeout(function () {
74577               context.map().on('move.intro', function () {
74578                 var entity = context.hasEntity(_pointID);
74579                 if (!entity) return chapter.restart();
74580                 var box = pointBox(entity.loc, context);
74581                 reveal(box, helpHtml('intro.points.' + textId), {
74582                   duration: 0
74583                 });
74584               });
74585             }, 600); // after reveal
74586
74587             context.on('enter.intro', function (mode) {
74588               if (mode.id !== 'select') return;
74589               var ids = context.selectedIDs();
74590               if (ids.length !== 1 || ids[0] !== _pointID) return;
74591               timeout(function () {
74592                 var node = selectMenuItem(context, 'delete').node();
74593                 if (!node) return;
74594                 continueTo(enterDelete);
74595               }, 50); // after menu visible
74596             });
74597
74598             function continueTo(nextStep) {
74599               context.on('enter.intro', null);
74600               context.map().on('move.intro', null);
74601               nextStep();
74602             }
74603           }
74604
74605           function enterDelete() {
74606             if (!_pointID) return chapter.restart();
74607             var entity = context.hasEntity(_pointID);
74608             if (!entity) return chapter.restart();
74609             var node = selectMenuItem(context, 'delete').node();
74610
74611             if (!node) {
74612               return continueTo(rightClickPoint);
74613             }
74614
74615             reveal('.edit-menu', helpHtml('intro.points.delete'), {
74616               padding: 50
74617             });
74618             timeout(function () {
74619               context.map().on('move.intro', function () {
74620                 reveal('.edit-menu', helpHtml('intro.points.delete'), {
74621                   duration: 0,
74622                   padding: 50
74623                 });
74624               });
74625             }, 300); // after menu visible
74626
74627             context.on('exit.intro', function () {
74628               if (!_pointID) return chapter.restart();
74629               var entity = context.hasEntity(_pointID);
74630               if (entity) return continueTo(rightClickPoint); // point still exists
74631             });
74632             context.history().on('change.intro', function (changed) {
74633               if (changed.deleted().length) {
74634                 continueTo(undo);
74635               }
74636             });
74637
74638             function continueTo(nextStep) {
74639               context.map().on('move.intro', null);
74640               context.history().on('change.intro', null);
74641               context.on('exit.intro', null);
74642               nextStep();
74643             }
74644           }
74645
74646           function undo() {
74647             context.history().on('change.intro', function () {
74648               continueTo(play);
74649             });
74650             reveal('.top-toolbar button.undo-button', helpHtml('intro.points.undo'));
74651
74652             function continueTo(nextStep) {
74653               context.history().on('change.intro', null);
74654               nextStep();
74655             }
74656           }
74657
74658           function play() {
74659             dispatch.call('done');
74660             reveal('.ideditor', helpHtml('intro.points.play', {
74661               next: _t('intro.areas.title')
74662             }), {
74663               tooltipBox: '.intro-nav-wrap .chapter-area',
74664               buttonText: _t.html('intro.ok'),
74665               buttonCallback: function buttonCallback() {
74666                 reveal('.ideditor');
74667               }
74668             });
74669           }
74670
74671           chapter.enter = function () {
74672             addPoint();
74673           };
74674
74675           chapter.exit = function () {
74676             timeouts.forEach(window.clearTimeout);
74677             context.on('enter.intro exit.intro', null);
74678             context.map().on('move.intro drawn.intro', null);
74679             context.history().on('change.intro', null);
74680             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74681             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
74682           };
74683
74684           chapter.restart = function () {
74685             chapter.exit();
74686             chapter.enter();
74687           };
74688
74689           return utilRebind(chapter, dispatch, 'on');
74690         }
74691
74692         function uiIntroArea(context, reveal) {
74693           var dispatch = dispatch$8('done');
74694           var playground = [-85.63552, 41.94159];
74695           var playgroundPreset = _mainPresetIndex.item('leisure/playground');
74696           var nameField = _mainPresetIndex.field('name');
74697           var descriptionField = _mainPresetIndex.field('description');
74698           var timeouts = [];
74699
74700           var _areaID;
74701
74702           var chapter = {
74703             title: 'intro.areas.title'
74704           };
74705
74706           function timeout(f, t) {
74707             timeouts.push(window.setTimeout(f, t));
74708           }
74709
74710           function eventCancel(d3_event) {
74711             d3_event.stopPropagation();
74712             d3_event.preventDefault();
74713           }
74714
74715           function revealPlayground(center, text, options) {
74716             var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
74717             var box = pad(center, padding, context);
74718             reveal(box, text, options);
74719           }
74720
74721           function addArea() {
74722             context.enter(modeBrowse(context));
74723             context.history().reset('initial');
74724             _areaID = null;
74725             var msec = transitionTime(playground, context.map().center());
74726
74727             if (msec) {
74728               reveal(null, null, {
74729                 duration: 0
74730               });
74731             }
74732
74733             context.map().centerZoomEase(playground, 19, msec);
74734             timeout(function () {
74735               var tooltip = reveal('button.add-area', helpHtml('intro.areas.add_playground'));
74736               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-areas');
74737               context.on('enter.intro', function (mode) {
74738                 if (mode.id !== 'add-area') return;
74739                 continueTo(startPlayground);
74740               });
74741             }, msec + 100);
74742
74743             function continueTo(nextStep) {
74744               context.on('enter.intro', null);
74745               nextStep();
74746             }
74747           }
74748
74749           function startPlayground() {
74750             if (context.mode().id !== 'add-area') {
74751               return chapter.restart();
74752             }
74753
74754             _areaID = null;
74755             context.map().zoomEase(19.5, 500);
74756             timeout(function () {
74757               var textId = context.lastPointerType() === 'mouse' ? 'starting_node_click' : 'starting_node_tap';
74758               var startDrawString = helpHtml('intro.areas.start_playground') + helpHtml('intro.areas.' + textId);
74759               revealPlayground(playground, startDrawString, {
74760                 duration: 250
74761               });
74762               timeout(function () {
74763                 context.map().on('move.intro drawn.intro', function () {
74764                   revealPlayground(playground, startDrawString, {
74765                     duration: 0
74766                   });
74767                 });
74768                 context.on('enter.intro', function (mode) {
74769                   if (mode.id !== 'draw-area') return chapter.restart();
74770                   continueTo(continuePlayground);
74771                 });
74772               }, 250); // after reveal
74773             }, 550); // after easing
74774
74775             function continueTo(nextStep) {
74776               context.map().on('move.intro drawn.intro', null);
74777               context.on('enter.intro', null);
74778               nextStep();
74779             }
74780           }
74781
74782           function continuePlayground() {
74783             if (context.mode().id !== 'draw-area') {
74784               return chapter.restart();
74785             }
74786
74787             _areaID = null;
74788             revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
74789               duration: 250
74790             });
74791             timeout(function () {
74792               context.map().on('move.intro drawn.intro', function () {
74793                 revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
74794                   duration: 0
74795                 });
74796               });
74797             }, 250); // after reveal
74798
74799             context.on('enter.intro', function (mode) {
74800               if (mode.id === 'draw-area') {
74801                 var entity = context.hasEntity(context.selectedIDs()[0]);
74802
74803                 if (entity && entity.nodes.length >= 6) {
74804                   return continueTo(finishPlayground);
74805                 } else {
74806                   return;
74807                 }
74808               } else if (mode.id === 'select') {
74809                 _areaID = context.selectedIDs()[0];
74810                 return continueTo(searchPresets);
74811               } else {
74812                 return chapter.restart();
74813               }
74814             });
74815
74816             function continueTo(nextStep) {
74817               context.map().on('move.intro drawn.intro', null);
74818               context.on('enter.intro', null);
74819               nextStep();
74820             }
74821           }
74822
74823           function finishPlayground() {
74824             if (context.mode().id !== 'draw-area') {
74825               return chapter.restart();
74826             }
74827
74828             _areaID = null;
74829             var finishString = helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.areas.finish_playground');
74830             revealPlayground(playground, finishString, {
74831               duration: 250
74832             });
74833             timeout(function () {
74834               context.map().on('move.intro drawn.intro', function () {
74835                 revealPlayground(playground, finishString, {
74836                   duration: 0
74837                 });
74838               });
74839             }, 250); // after reveal
74840
74841             context.on('enter.intro', function (mode) {
74842               if (mode.id === 'draw-area') {
74843                 return;
74844               } else if (mode.id === 'select') {
74845                 _areaID = context.selectedIDs()[0];
74846                 return continueTo(searchPresets);
74847               } else {
74848                 return chapter.restart();
74849               }
74850             });
74851
74852             function continueTo(nextStep) {
74853               context.map().on('move.intro drawn.intro', null);
74854               context.on('enter.intro', null);
74855               nextStep();
74856             }
74857           }
74858
74859           function searchPresets() {
74860             if (!_areaID || !context.hasEntity(_areaID)) {
74861               return addArea();
74862             }
74863
74864             var ids = context.selectedIDs();
74865
74866             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
74867               context.enter(modeSelect(context, [_areaID]));
74868             } // disallow scrolling
74869
74870
74871             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74872             timeout(function () {
74873               // reset pane, in case user somehow happened to change it..
74874               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
74875               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
74876               reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
74877                 preset: playgroundPreset.name()
74878               }));
74879             }, 400); // after preset list pane visible..
74880
74881             context.on('enter.intro', function (mode) {
74882               if (!_areaID || !context.hasEntity(_areaID)) {
74883                 return continueTo(addArea);
74884               }
74885
74886               var ids = context.selectedIDs();
74887
74888               if (mode.id !== 'select' || !ids.length || ids[0] !== _areaID) {
74889                 // keep the user's area selected..
74890                 context.enter(modeSelect(context, [_areaID])); // reset pane, in case user somehow happened to change it..
74891
74892                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
74893
74894                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74895                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
74896                 reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
74897                   preset: playgroundPreset.name()
74898                 }));
74899                 context.history().on('change.intro', null);
74900               }
74901             });
74902
74903             function checkPresetSearch() {
74904               var first = context.container().select('.preset-list-item:first-child');
74905
74906               if (first.classed('preset-leisure-playground')) {
74907                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.areas.choose_playground', {
74908                   preset: playgroundPreset.name()
74909                 }), {
74910                   duration: 300
74911                 });
74912                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
74913                 context.history().on('change.intro', function () {
74914                   continueTo(clickAddField);
74915                 });
74916               }
74917             }
74918
74919             function continueTo(nextStep) {
74920               context.container().select('.inspector-wrap').on('wheel.intro', null);
74921               context.on('enter.intro', null);
74922               context.history().on('change.intro', null);
74923               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
74924               nextStep();
74925             }
74926           }
74927
74928           function clickAddField() {
74929             if (!_areaID || !context.hasEntity(_areaID)) {
74930               return addArea();
74931             }
74932
74933             var ids = context.selectedIDs();
74934
74935             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
74936               return searchPresets();
74937             }
74938
74939             if (!context.container().select('.form-field-description').empty()) {
74940               return continueTo(describePlayground);
74941             } // disallow scrolling
74942
74943
74944             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74945             timeout(function () {
74946               // reset pane, in case user somehow happened to change it..
74947               context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // It's possible for the user to add a description in a previous step..
74948               // If they did this already, just continue to next step.
74949
74950               var entity = context.entity(_areaID);
74951
74952               if (entity.tags.description) {
74953                 return continueTo(play);
74954               } // scroll "Add field" into view
74955
74956
74957               var box = context.container().select('.more-fields').node().getBoundingClientRect();
74958
74959               if (box.top > 300) {
74960                 var pane = context.container().select('.entity-editor-pane .inspector-body');
74961                 var start = pane.node().scrollTop;
74962                 var end = start + (box.top - 300);
74963                 pane.transition().duration(250).tween('scroll.inspector', function () {
74964                   var node = this;
74965                   var i = d3_interpolateNumber(start, end);
74966                   return function (t) {
74967                     node.scrollTop = i(t);
74968                   };
74969                 });
74970               }
74971
74972               timeout(function () {
74973                 reveal('.more-fields .combobox-input', helpHtml('intro.areas.add_field', {
74974                   name: nameField.label(),
74975                   description: descriptionField.label()
74976                 }), {
74977                   duration: 300
74978                 });
74979                 context.container().select('.more-fields .combobox-input').on('click.intro', function () {
74980                   // Watch for the combobox to appear...
74981                   var watcher;
74982                   watcher = window.setInterval(function () {
74983                     if (!context.container().select('div.combobox').empty()) {
74984                       window.clearInterval(watcher);
74985                       continueTo(chooseDescriptionField);
74986                     }
74987                   }, 300);
74988                 });
74989               }, 300); // after "Add Field" visible
74990             }, 400); // after editor pane visible
74991
74992             context.on('exit.intro', function () {
74993               return continueTo(searchPresets);
74994             });
74995
74996             function continueTo(nextStep) {
74997               context.container().select('.inspector-wrap').on('wheel.intro', null);
74998               context.container().select('.more-fields .combobox-input').on('click.intro', null);
74999               context.on('exit.intro', null);
75000               nextStep();
75001             }
75002           }
75003
75004           function chooseDescriptionField() {
75005             if (!_areaID || !context.hasEntity(_areaID)) {
75006               return addArea();
75007             }
75008
75009             var ids = context.selectedIDs();
75010
75011             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
75012               return searchPresets();
75013             }
75014
75015             if (!context.container().select('.form-field-description').empty()) {
75016               return continueTo(describePlayground);
75017             } // Make sure combobox is ready..
75018
75019
75020             if (context.container().select('div.combobox').empty()) {
75021               return continueTo(clickAddField);
75022             } // Watch for the combobox to go away..
75023
75024
75025             var watcher;
75026             watcher = window.setInterval(function () {
75027               if (context.container().select('div.combobox').empty()) {
75028                 window.clearInterval(watcher);
75029                 timeout(function () {
75030                   if (context.container().select('.form-field-description').empty()) {
75031                     continueTo(retryChooseDescription);
75032                   } else {
75033                     continueTo(describePlayground);
75034                   }
75035                 }, 300); // after description field added.
75036               }
75037             }, 300);
75038             reveal('div.combobox', helpHtml('intro.areas.choose_field', {
75039               field: descriptionField.label()
75040             }), {
75041               duration: 300
75042             });
75043             context.on('exit.intro', function () {
75044               return continueTo(searchPresets);
75045             });
75046
75047             function continueTo(nextStep) {
75048               if (watcher) window.clearInterval(watcher);
75049               context.on('exit.intro', null);
75050               nextStep();
75051             }
75052           }
75053
75054           function describePlayground() {
75055             if (!_areaID || !context.hasEntity(_areaID)) {
75056               return addArea();
75057             }
75058
75059             var ids = context.selectedIDs();
75060
75061             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
75062               return searchPresets();
75063             } // reset pane, in case user happened to change it..
75064
75065
75066             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
75067
75068             if (context.container().select('.form-field-description').empty()) {
75069               return continueTo(retryChooseDescription);
75070             }
75071
75072             context.on('exit.intro', function () {
75073               continueTo(play);
75074             });
75075             reveal('.entity-editor-pane', helpHtml('intro.areas.describe_playground', {
75076               button: icon('#iD-icon-close', 'inline')
75077             }), {
75078               duration: 300
75079             });
75080
75081             function continueTo(nextStep) {
75082               context.on('exit.intro', null);
75083               nextStep();
75084             }
75085           }
75086
75087           function retryChooseDescription() {
75088             if (!_areaID || !context.hasEntity(_areaID)) {
75089               return addArea();
75090             }
75091
75092             var ids = context.selectedIDs();
75093
75094             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
75095               return searchPresets();
75096             } // reset pane, in case user happened to change it..
75097
75098
75099             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
75100             reveal('.entity-editor-pane', helpHtml('intro.areas.retry_add_field', {
75101               field: descriptionField.label()
75102             }), {
75103               buttonText: _t.html('intro.ok'),
75104               buttonCallback: function buttonCallback() {
75105                 continueTo(clickAddField);
75106               }
75107             });
75108             context.on('exit.intro', function () {
75109               return continueTo(searchPresets);
75110             });
75111
75112             function continueTo(nextStep) {
75113               context.on('exit.intro', null);
75114               nextStep();
75115             }
75116           }
75117
75118           function play() {
75119             dispatch.call('done');
75120             reveal('.ideditor', helpHtml('intro.areas.play', {
75121               next: _t('intro.lines.title')
75122             }), {
75123               tooltipBox: '.intro-nav-wrap .chapter-line',
75124               buttonText: _t.html('intro.ok'),
75125               buttonCallback: function buttonCallback() {
75126                 reveal('.ideditor');
75127               }
75128             });
75129           }
75130
75131           chapter.enter = function () {
75132             addArea();
75133           };
75134
75135           chapter.exit = function () {
75136             timeouts.forEach(window.clearTimeout);
75137             context.on('enter.intro exit.intro', null);
75138             context.map().on('move.intro drawn.intro', null);
75139             context.history().on('change.intro', null);
75140             context.container().select('.inspector-wrap').on('wheel.intro', null);
75141             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
75142             context.container().select('.more-fields .combobox-input').on('click.intro', null);
75143           };
75144
75145           chapter.restart = function () {
75146             chapter.exit();
75147             chapter.enter();
75148           };
75149
75150           return utilRebind(chapter, dispatch, 'on');
75151         }
75152
75153         function uiIntroLine(context, reveal) {
75154           var dispatch = dispatch$8('done');
75155           var timeouts = [];
75156           var _tulipRoadID = null;
75157           var flowerRoadID = 'w646';
75158           var tulipRoadStart = [-85.6297754121684, 41.95805253325314];
75159           var tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204];
75160           var tulipRoadIntersection = [-85.62974496187628, 41.95742515554585];
75161           var roadCategory = _mainPresetIndex.item('category-road_minor');
75162           var residentialPreset = _mainPresetIndex.item('highway/residential');
75163           var woodRoadID = 'w525';
75164           var woodRoadEndID = 'n2862';
75165           var woodRoadAddNode = [-85.62390110349587, 41.95397111462291];
75166           var woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487];
75167           var woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872];
75168           var washingtonStreetID = 'w522';
75169           var twelfthAvenueID = 'w1';
75170           var eleventhAvenueEndID = 'n3550';
75171           var twelfthAvenueEndID = 'n5';
75172           var _washingtonSegmentID = null;
75173           var eleventhAvenueEnd = context.entity(eleventhAvenueEndID).loc;
75174           var twelfthAvenueEnd = context.entity(twelfthAvenueEndID).loc;
75175           var deleteLinesLoc = [-85.6219395542764, 41.95228033922477];
75176           var twelfthAvenue = [-85.62219310052491, 41.952505413152956];
75177           var chapter = {
75178             title: 'intro.lines.title'
75179           };
75180
75181           function timeout(f, t) {
75182             timeouts.push(window.setTimeout(f, t));
75183           }
75184
75185           function eventCancel(d3_event) {
75186             d3_event.stopPropagation();
75187             d3_event.preventDefault();
75188           }
75189
75190           function addLine() {
75191             context.enter(modeBrowse(context));
75192             context.history().reset('initial');
75193             var msec = transitionTime(tulipRoadStart, context.map().center());
75194
75195             if (msec) {
75196               reveal(null, null, {
75197                 duration: 0
75198               });
75199             }
75200
75201             context.map().centerZoomEase(tulipRoadStart, 18.5, msec);
75202             timeout(function () {
75203               var tooltip = reveal('button.add-line', helpHtml('intro.lines.add_line'));
75204               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-lines');
75205               context.on('enter.intro', function (mode) {
75206                 if (mode.id !== 'add-line') return;
75207                 continueTo(startLine);
75208               });
75209             }, msec + 100);
75210
75211             function continueTo(nextStep) {
75212               context.on('enter.intro', null);
75213               nextStep();
75214             }
75215           }
75216
75217           function startLine() {
75218             if (context.mode().id !== 'add-line') return chapter.restart();
75219             _tulipRoadID = null;
75220             var padding = 70 * Math.pow(2, context.map().zoom() - 18);
75221             var box = pad(tulipRoadStart, padding, context);
75222             box.height = box.height + 100;
75223             var textId = context.lastPointerType() === 'mouse' ? 'start_line' : 'start_line_tap';
75224             var startLineString = helpHtml('intro.lines.missing_road') + '{br}' + helpHtml('intro.lines.line_draw_info') + helpHtml('intro.lines.' + textId);
75225             reveal(box, startLineString);
75226             context.map().on('move.intro drawn.intro', function () {
75227               padding = 70 * Math.pow(2, context.map().zoom() - 18);
75228               box = pad(tulipRoadStart, padding, context);
75229               box.height = box.height + 100;
75230               reveal(box, startLineString, {
75231                 duration: 0
75232               });
75233             });
75234             context.on('enter.intro', function (mode) {
75235               if (mode.id !== 'draw-line') return chapter.restart();
75236               continueTo(drawLine);
75237             });
75238
75239             function continueTo(nextStep) {
75240               context.map().on('move.intro drawn.intro', null);
75241               context.on('enter.intro', null);
75242               nextStep();
75243             }
75244           }
75245
75246           function drawLine() {
75247             if (context.mode().id !== 'draw-line') return chapter.restart();
75248             _tulipRoadID = context.mode().selectedIDs()[0];
75249             context.map().centerEase(tulipRoadMidpoint, 500);
75250             timeout(function () {
75251               var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
75252               var box = pad(tulipRoadMidpoint, padding, context);
75253               box.height = box.height * 2;
75254               reveal(box, helpHtml('intro.lines.intersect', {
75255                 name: _t('intro.graph.name.flower-street')
75256               }));
75257               context.map().on('move.intro drawn.intro', function () {
75258                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
75259                 box = pad(tulipRoadMidpoint, padding, context);
75260                 box.height = box.height * 2;
75261                 reveal(box, helpHtml('intro.lines.intersect', {
75262                   name: _t('intro.graph.name.flower-street')
75263                 }), {
75264                   duration: 0
75265                 });
75266               });
75267             }, 550); // after easing..
75268
75269             context.history().on('change.intro', function () {
75270               if (isLineConnected()) {
75271                 continueTo(continueLine);
75272               }
75273             });
75274             context.on('enter.intro', function (mode) {
75275               if (mode.id === 'draw-line') {
75276                 return;
75277               } else if (mode.id === 'select') {
75278                 continueTo(retryIntersect);
75279                 return;
75280               } else {
75281                 return chapter.restart();
75282               }
75283             });
75284
75285             function continueTo(nextStep) {
75286               context.map().on('move.intro drawn.intro', null);
75287               context.history().on('change.intro', null);
75288               context.on('enter.intro', null);
75289               nextStep();
75290             }
75291           }
75292
75293           function isLineConnected() {
75294             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
75295
75296             if (!entity) return false;
75297             var drawNodes = context.graph().childNodes(entity);
75298             return drawNodes.some(function (node) {
75299               return context.graph().parentWays(node).some(function (parent) {
75300                 return parent.id === flowerRoadID;
75301               });
75302             });
75303           }
75304
75305           function retryIntersect() {
75306             select(window).on('pointerdown.intro mousedown.intro', eventCancel, true);
75307             var box = pad(tulipRoadIntersection, 80, context);
75308             reveal(box, helpHtml('intro.lines.retry_intersect', {
75309               name: _t('intro.graph.name.flower-street')
75310             }));
75311             timeout(chapter.restart, 3000);
75312           }
75313
75314           function continueLine() {
75315             if (context.mode().id !== 'draw-line') return chapter.restart();
75316
75317             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
75318
75319             if (!entity) return chapter.restart();
75320             context.map().centerEase(tulipRoadIntersection, 500);
75321             var continueLineText = helpHtml('intro.lines.continue_line') + '{br}' + helpHtml('intro.lines.finish_line_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.lines.finish_road');
75322             reveal('.surface', continueLineText);
75323             context.on('enter.intro', function (mode) {
75324               if (mode.id === 'draw-line') {
75325                 return;
75326               } else if (mode.id === 'select') {
75327                 return continueTo(chooseCategoryRoad);
75328               } else {
75329                 return chapter.restart();
75330               }
75331             });
75332
75333             function continueTo(nextStep) {
75334               context.on('enter.intro', null);
75335               nextStep();
75336             }
75337           }
75338
75339           function chooseCategoryRoad() {
75340             if (context.mode().id !== 'select') return chapter.restart();
75341             context.on('exit.intro', function () {
75342               return chapter.restart();
75343             });
75344             var button = context.container().select('.preset-category-road_minor .preset-list-button');
75345             if (button.empty()) return chapter.restart(); // disallow scrolling
75346
75347             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75348             timeout(function () {
75349               // reset pane, in case user somehow happened to change it..
75350               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
75351               reveal(button.node(), helpHtml('intro.lines.choose_category_road', {
75352                 category: roadCategory.name()
75353               }));
75354               button.on('click.intro', function () {
75355                 continueTo(choosePresetResidential);
75356               });
75357             }, 400); // after editor pane visible
75358
75359             function continueTo(nextStep) {
75360               context.container().select('.inspector-wrap').on('wheel.intro', null);
75361               context.container().select('.preset-list-button').on('click.intro', null);
75362               context.on('exit.intro', null);
75363               nextStep();
75364             }
75365           }
75366
75367           function choosePresetResidential() {
75368             if (context.mode().id !== 'select') return chapter.restart();
75369             context.on('exit.intro', function () {
75370               return chapter.restart();
75371             });
75372             var subgrid = context.container().select('.preset-category-road_minor .subgrid');
75373             if (subgrid.empty()) return chapter.restart();
75374             subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button').on('click.intro', function () {
75375               continueTo(retryPresetResidential);
75376             });
75377             subgrid.selectAll('.preset-highway-residential .preset-list-button').on('click.intro', function () {
75378               continueTo(nameRoad);
75379             });
75380             timeout(function () {
75381               reveal(subgrid.node(), helpHtml('intro.lines.choose_preset_residential', {
75382                 preset: residentialPreset.name()
75383               }), {
75384                 tooltipBox: '.preset-highway-residential .preset-list-button',
75385                 duration: 300
75386               });
75387             }, 300);
75388
75389             function continueTo(nextStep) {
75390               context.container().select('.preset-list-button').on('click.intro', null);
75391               context.on('exit.intro', null);
75392               nextStep();
75393             }
75394           } // selected wrong road type
75395
75396
75397           function retryPresetResidential() {
75398             if (context.mode().id !== 'select') return chapter.restart();
75399             context.on('exit.intro', function () {
75400               return chapter.restart();
75401             }); // disallow scrolling
75402
75403             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75404             timeout(function () {
75405               var button = context.container().select('.entity-editor-pane .preset-list-button');
75406               reveal(button.node(), helpHtml('intro.lines.retry_preset_residential', {
75407                 preset: residentialPreset.name()
75408               }));
75409               button.on('click.intro', function () {
75410                 continueTo(chooseCategoryRoad);
75411               });
75412             }, 500);
75413
75414             function continueTo(nextStep) {
75415               context.container().select('.inspector-wrap').on('wheel.intro', null);
75416               context.container().select('.preset-list-button').on('click.intro', null);
75417               context.on('exit.intro', null);
75418               nextStep();
75419             }
75420           }
75421
75422           function nameRoad() {
75423             context.on('exit.intro', function () {
75424               continueTo(didNameRoad);
75425             });
75426             timeout(function () {
75427               reveal('.entity-editor-pane', helpHtml('intro.lines.name_road', {
75428                 button: icon('#iD-icon-close', 'inline')
75429               }), {
75430                 tooltipClass: 'intro-lines-name_road'
75431               });
75432             }, 500);
75433
75434             function continueTo(nextStep) {
75435               context.on('exit.intro', null);
75436               nextStep();
75437             }
75438           }
75439
75440           function didNameRoad() {
75441             context.history().checkpoint('doneAddLine');
75442             timeout(function () {
75443               reveal('.surface', helpHtml('intro.lines.did_name_road'), {
75444                 buttonText: _t.html('intro.ok'),
75445                 buttonCallback: function buttonCallback() {
75446                   continueTo(updateLine);
75447                 }
75448               });
75449             }, 500);
75450
75451             function continueTo(nextStep) {
75452               nextStep();
75453             }
75454           }
75455
75456           function updateLine() {
75457             context.history().reset('doneAddLine');
75458
75459             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75460               return chapter.restart();
75461             }
75462
75463             var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
75464
75465             if (msec) {
75466               reveal(null, null, {
75467                 duration: 0
75468               });
75469             }
75470
75471             context.map().centerZoomEase(woodRoadDragMidpoint, 19, msec);
75472             timeout(function () {
75473               var padding = 250 * Math.pow(2, context.map().zoom() - 19);
75474               var box = pad(woodRoadDragMidpoint, padding, context);
75475
75476               var advance = function advance() {
75477                 continueTo(addNode);
75478               };
75479
75480               reveal(box, helpHtml('intro.lines.update_line'), {
75481                 buttonText: _t.html('intro.ok'),
75482                 buttonCallback: advance
75483               });
75484               context.map().on('move.intro drawn.intro', function () {
75485                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
75486                 var box = pad(woodRoadDragMidpoint, padding, context);
75487                 reveal(box, helpHtml('intro.lines.update_line'), {
75488                   duration: 0,
75489                   buttonText: _t.html('intro.ok'),
75490                   buttonCallback: advance
75491                 });
75492               });
75493             }, msec + 100);
75494
75495             function continueTo(nextStep) {
75496               context.map().on('move.intro drawn.intro', null);
75497               nextStep();
75498             }
75499           }
75500
75501           function addNode() {
75502             context.history().reset('doneAddLine');
75503
75504             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75505               return chapter.restart();
75506             }
75507
75508             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
75509             var box = pad(woodRoadAddNode, padding, context);
75510             var addNodeString = helpHtml('intro.lines.add_node' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
75511             reveal(box, addNodeString);
75512             context.map().on('move.intro drawn.intro', function () {
75513               var padding = 40 * Math.pow(2, context.map().zoom() - 19);
75514               var box = pad(woodRoadAddNode, padding, context);
75515               reveal(box, addNodeString, {
75516                 duration: 0
75517               });
75518             });
75519             context.history().on('change.intro', function (changed) {
75520               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75521                 return continueTo(updateLine);
75522               }
75523
75524               if (changed.created().length === 1) {
75525                 timeout(function () {
75526                   continueTo(startDragEndpoint);
75527                 }, 500);
75528               }
75529             });
75530             context.on('enter.intro', function (mode) {
75531               if (mode.id !== 'select') {
75532                 continueTo(updateLine);
75533               }
75534             });
75535
75536             function continueTo(nextStep) {
75537               context.map().on('move.intro drawn.intro', null);
75538               context.history().on('change.intro', null);
75539               context.on('enter.intro', null);
75540               nextStep();
75541             }
75542           }
75543
75544           function startDragEndpoint() {
75545             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75546               return continueTo(updateLine);
75547             }
75548
75549             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
75550             var box = pad(woodRoadDragEndpoint, padding, context);
75551             var startDragString = helpHtml('intro.lines.start_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch')) + helpHtml('intro.lines.drag_to_intersection');
75552             reveal(box, startDragString);
75553             context.map().on('move.intro drawn.intro', function () {
75554               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75555                 return continueTo(updateLine);
75556               }
75557
75558               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
75559               var box = pad(woodRoadDragEndpoint, padding, context);
75560               reveal(box, startDragString, {
75561                 duration: 0
75562               });
75563               var entity = context.entity(woodRoadEndID);
75564
75565               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
75566                 continueTo(finishDragEndpoint);
75567               }
75568             });
75569
75570             function continueTo(nextStep) {
75571               context.map().on('move.intro drawn.intro', null);
75572               nextStep();
75573             }
75574           }
75575
75576           function finishDragEndpoint() {
75577             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75578               return continueTo(updateLine);
75579             }
75580
75581             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
75582             var box = pad(woodRoadDragEndpoint, padding, context);
75583             var finishDragString = helpHtml('intro.lines.spot_looks_good') + helpHtml('intro.lines.finish_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
75584             reveal(box, finishDragString);
75585             context.map().on('move.intro drawn.intro', function () {
75586               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75587                 return continueTo(updateLine);
75588               }
75589
75590               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
75591               var box = pad(woodRoadDragEndpoint, padding, context);
75592               reveal(box, finishDragString, {
75593                 duration: 0
75594               });
75595               var entity = context.entity(woodRoadEndID);
75596
75597               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
75598                 continueTo(startDragEndpoint);
75599               }
75600             });
75601             context.on('enter.intro', function () {
75602               continueTo(startDragMidpoint);
75603             });
75604
75605             function continueTo(nextStep) {
75606               context.map().on('move.intro drawn.intro', null);
75607               context.on('enter.intro', null);
75608               nextStep();
75609             }
75610           }
75611
75612           function startDragMidpoint() {
75613             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75614               return continueTo(updateLine);
75615             }
75616
75617             if (context.selectedIDs().indexOf(woodRoadID) === -1) {
75618               context.enter(modeSelect(context, [woodRoadID]));
75619             }
75620
75621             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
75622             var box = pad(woodRoadDragMidpoint, padding, context);
75623             reveal(box, helpHtml('intro.lines.start_drag_midpoint'));
75624             context.map().on('move.intro drawn.intro', function () {
75625               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75626                 return continueTo(updateLine);
75627               }
75628
75629               var padding = 80 * Math.pow(2, context.map().zoom() - 19);
75630               var box = pad(woodRoadDragMidpoint, padding, context);
75631               reveal(box, helpHtml('intro.lines.start_drag_midpoint'), {
75632                 duration: 0
75633               });
75634             });
75635             context.history().on('change.intro', function (changed) {
75636               if (changed.created().length === 1) {
75637                 continueTo(continueDragMidpoint);
75638               }
75639             });
75640             context.on('enter.intro', function (mode) {
75641               if (mode.id !== 'select') {
75642                 // keep Wood Road selected so midpoint triangles are drawn..
75643                 context.enter(modeSelect(context, [woodRoadID]));
75644               }
75645             });
75646
75647             function continueTo(nextStep) {
75648               context.map().on('move.intro drawn.intro', null);
75649               context.history().on('change.intro', null);
75650               context.on('enter.intro', null);
75651               nextStep();
75652             }
75653           }
75654
75655           function continueDragMidpoint() {
75656             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75657               return continueTo(updateLine);
75658             }
75659
75660             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
75661             var box = pad(woodRoadDragEndpoint, padding, context);
75662             box.height += 400;
75663
75664             var advance = function advance() {
75665               context.history().checkpoint('doneUpdateLine');
75666               continueTo(deleteLines);
75667             };
75668
75669             reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
75670               buttonText: _t.html('intro.ok'),
75671               buttonCallback: advance
75672             });
75673             context.map().on('move.intro drawn.intro', function () {
75674               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
75675                 return continueTo(updateLine);
75676               }
75677
75678               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
75679               var box = pad(woodRoadDragEndpoint, padding, context);
75680               box.height += 400;
75681               reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
75682                 duration: 0,
75683                 buttonText: _t.html('intro.ok'),
75684                 buttonCallback: advance
75685               });
75686             });
75687
75688             function continueTo(nextStep) {
75689               context.map().on('move.intro drawn.intro', null);
75690               nextStep();
75691             }
75692           }
75693
75694           function deleteLines() {
75695             context.history().reset('doneUpdateLine');
75696             context.enter(modeBrowse(context));
75697
75698             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
75699               return chapter.restart();
75700             }
75701
75702             var msec = transitionTime(deleteLinesLoc, context.map().center());
75703
75704             if (msec) {
75705               reveal(null, null, {
75706                 duration: 0
75707               });
75708             }
75709
75710             context.map().centerZoomEase(deleteLinesLoc, 18, msec);
75711             timeout(function () {
75712               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
75713               var box = pad(deleteLinesLoc, padding, context);
75714               box.top -= 200;
75715               box.height += 400;
75716
75717               var advance = function advance() {
75718                 continueTo(rightClickIntersection);
75719               };
75720
75721               reveal(box, helpHtml('intro.lines.delete_lines', {
75722                 street: _t('intro.graph.name.12th-avenue')
75723               }), {
75724                 buttonText: _t.html('intro.ok'),
75725                 buttonCallback: advance
75726               });
75727               context.map().on('move.intro drawn.intro', function () {
75728                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
75729                 var box = pad(deleteLinesLoc, padding, context);
75730                 box.top -= 200;
75731                 box.height += 400;
75732                 reveal(box, helpHtml('intro.lines.delete_lines', {
75733                   street: _t('intro.graph.name.12th-avenue')
75734                 }), {
75735                   duration: 0,
75736                   buttonText: _t.html('intro.ok'),
75737                   buttonCallback: advance
75738                 });
75739               });
75740               context.history().on('change.intro', function () {
75741                 timeout(function () {
75742                   continueTo(deleteLines);
75743                 }, 500); // after any transition (e.g. if user deleted intersection)
75744               });
75745             }, msec + 100);
75746
75747             function continueTo(nextStep) {
75748               context.map().on('move.intro drawn.intro', null);
75749               context.history().on('change.intro', null);
75750               nextStep();
75751             }
75752           }
75753
75754           function rightClickIntersection() {
75755             context.history().reset('doneUpdateLine');
75756             context.enter(modeBrowse(context));
75757             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
75758             var rightClickString = helpHtml('intro.lines.split_street', {
75759               street1: _t('intro.graph.name.11th-avenue'),
75760               street2: _t('intro.graph.name.washington-street')
75761             }) + helpHtml('intro.lines.' + (context.lastPointerType() === 'mouse' ? 'rightclick_intersection' : 'edit_menu_intersection_touch'));
75762             timeout(function () {
75763               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
75764               var box = pad(eleventhAvenueEnd, padding, context);
75765               reveal(box, rightClickString);
75766               context.map().on('move.intro drawn.intro', function () {
75767                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
75768                 var box = pad(eleventhAvenueEnd, padding, context);
75769                 reveal(box, rightClickString, {
75770                   duration: 0
75771                 });
75772               });
75773               context.on('enter.intro', function (mode) {
75774                 if (mode.id !== 'select') return;
75775                 var ids = context.selectedIDs();
75776                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID) return;
75777                 timeout(function () {
75778                   var node = selectMenuItem(context, 'split').node();
75779                   if (!node) return;
75780                   continueTo(splitIntersection);
75781                 }, 50); // after menu visible
75782               });
75783               context.history().on('change.intro', function () {
75784                 timeout(function () {
75785                   continueTo(deleteLines);
75786                 }, 300); // after any transition (e.g. if user deleted intersection)
75787               });
75788             }, 600);
75789
75790             function continueTo(nextStep) {
75791               context.map().on('move.intro drawn.intro', null);
75792               context.on('enter.intro', null);
75793               context.history().on('change.intro', null);
75794               nextStep();
75795             }
75796           }
75797
75798           function splitIntersection() {
75799             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
75800               return continueTo(deleteLines);
75801             }
75802
75803             var node = selectMenuItem(context, 'split').node();
75804
75805             if (!node) {
75806               return continueTo(rightClickIntersection);
75807             }
75808
75809             var wasChanged = false;
75810             _washingtonSegmentID = null;
75811             reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
75812               street: _t('intro.graph.name.washington-street')
75813             }), {
75814               padding: 50
75815             });
75816             context.map().on('move.intro drawn.intro', function () {
75817               var node = selectMenuItem(context, 'split').node();
75818
75819               if (!wasChanged && !node) {
75820                 return continueTo(rightClickIntersection);
75821               }
75822
75823               reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
75824                 street: _t('intro.graph.name.washington-street')
75825               }), {
75826                 duration: 0,
75827                 padding: 50
75828               });
75829             });
75830             context.history().on('change.intro', function (changed) {
75831               wasChanged = true;
75832               timeout(function () {
75833                 if (context.history().undoAnnotation() === _t('operations.split.annotation.line', {
75834                   n: 1
75835                 })) {
75836                   _washingtonSegmentID = changed.created()[0].id;
75837                   continueTo(didSplit);
75838                 } else {
75839                   _washingtonSegmentID = null;
75840                   continueTo(retrySplit);
75841                 }
75842               }, 300); // after any transition (e.g. if user deleted intersection)
75843             });
75844
75845             function continueTo(nextStep) {
75846               context.map().on('move.intro drawn.intro', null);
75847               context.history().on('change.intro', null);
75848               nextStep();
75849             }
75850           }
75851
75852           function retrySplit() {
75853             context.enter(modeBrowse(context));
75854             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
75855
75856             var advance = function advance() {
75857               continueTo(rightClickIntersection);
75858             };
75859
75860             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
75861             var box = pad(eleventhAvenueEnd, padding, context);
75862             reveal(box, helpHtml('intro.lines.retry_split'), {
75863               buttonText: _t.html('intro.ok'),
75864               buttonCallback: advance
75865             });
75866             context.map().on('move.intro drawn.intro', function () {
75867               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
75868               var box = pad(eleventhAvenueEnd, padding, context);
75869               reveal(box, helpHtml('intro.lines.retry_split'), {
75870                 duration: 0,
75871                 buttonText: _t.html('intro.ok'),
75872                 buttonCallback: advance
75873               });
75874             });
75875
75876             function continueTo(nextStep) {
75877               context.map().on('move.intro drawn.intro', null);
75878               nextStep();
75879             }
75880           }
75881
75882           function didSplit() {
75883             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
75884               return continueTo(rightClickIntersection);
75885             }
75886
75887             var ids = context.selectedIDs();
75888             var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
75889             var street = _t('intro.graph.name.washington-street');
75890             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
75891             var box = pad(twelfthAvenue, padding, context);
75892             box.width = box.width / 2;
75893             reveal(box, helpHtml(string, {
75894               street1: street,
75895               street2: street
75896             }), {
75897               duration: 500
75898             });
75899             timeout(function () {
75900               context.map().centerZoomEase(twelfthAvenue, 18, 500);
75901               context.map().on('move.intro drawn.intro', function () {
75902                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
75903                 var box = pad(twelfthAvenue, padding, context);
75904                 box.width = box.width / 2;
75905                 reveal(box, helpHtml(string, {
75906                   street1: street,
75907                   street2: street
75908                 }), {
75909                   duration: 0
75910                 });
75911               });
75912             }, 600); // after initial reveal and curtain cut
75913
75914             context.on('enter.intro', function () {
75915               var ids = context.selectedIDs();
75916
75917               if (ids.length === 1 && ids[0] === _washingtonSegmentID) {
75918                 continueTo(multiSelect);
75919               }
75920             });
75921             context.history().on('change.intro', function () {
75922               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
75923                 return continueTo(rightClickIntersection);
75924               }
75925             });
75926
75927             function continueTo(nextStep) {
75928               context.map().on('move.intro drawn.intro', null);
75929               context.on('enter.intro', null);
75930               context.history().on('change.intro', null);
75931               nextStep();
75932             }
75933           }
75934
75935           function multiSelect() {
75936             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
75937               return continueTo(rightClickIntersection);
75938             }
75939
75940             var ids = context.selectedIDs();
75941             var hasWashington = ids.indexOf(_washingtonSegmentID) !== -1;
75942             var hasTwelfth = ids.indexOf(twelfthAvenueID) !== -1;
75943
75944             if (hasWashington && hasTwelfth) {
75945               return continueTo(multiRightClick);
75946             } else if (!hasWashington && !hasTwelfth) {
75947               return continueTo(didSplit);
75948             }
75949
75950             context.map().centerZoomEase(twelfthAvenue, 18, 500);
75951             timeout(function () {
75952               var selected, other, padding, box;
75953
75954               if (hasWashington) {
75955                 selected = _t('intro.graph.name.washington-street');
75956                 other = _t('intro.graph.name.12th-avenue');
75957                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
75958                 box = pad(twelfthAvenueEnd, padding, context);
75959                 box.width *= 3;
75960               } else {
75961                 selected = _t('intro.graph.name.12th-avenue');
75962                 other = _t('intro.graph.name.washington-street');
75963                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
75964                 box = pad(twelfthAvenue, padding, context);
75965                 box.width /= 2;
75966               }
75967
75968               reveal(box, helpHtml('intro.lines.multi_select', {
75969                 selected: selected,
75970                 other1: other
75971               }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
75972                 selected: selected,
75973                 other2: other
75974               }));
75975               context.map().on('move.intro drawn.intro', function () {
75976                 if (hasWashington) {
75977                   selected = _t('intro.graph.name.washington-street');
75978                   other = _t('intro.graph.name.12th-avenue');
75979                   padding = 60 * Math.pow(2, context.map().zoom() - 18);
75980                   box = pad(twelfthAvenueEnd, padding, context);
75981                   box.width *= 3;
75982                 } else {
75983                   selected = _t('intro.graph.name.12th-avenue');
75984                   other = _t('intro.graph.name.washington-street');
75985                   padding = 200 * Math.pow(2, context.map().zoom() - 18);
75986                   box = pad(twelfthAvenue, padding, context);
75987                   box.width /= 2;
75988                 }
75989
75990                 reveal(box, helpHtml('intro.lines.multi_select', {
75991                   selected: selected,
75992                   other1: other
75993                 }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
75994                   selected: selected,
75995                   other2: other
75996                 }), {
75997                   duration: 0
75998                 });
75999               });
76000               context.on('enter.intro', function () {
76001                 continueTo(multiSelect);
76002               });
76003               context.history().on('change.intro', function () {
76004                 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
76005                   return continueTo(rightClickIntersection);
76006                 }
76007               });
76008             }, 600);
76009
76010             function continueTo(nextStep) {
76011               context.map().on('move.intro drawn.intro', null);
76012               context.on('enter.intro', null);
76013               context.history().on('change.intro', null);
76014               nextStep();
76015             }
76016           }
76017
76018           function multiRightClick() {
76019             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
76020               return continueTo(rightClickIntersection);
76021             }
76022
76023             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
76024             var box = pad(twelfthAvenue, padding, context);
76025             var rightClickString = helpHtml('intro.lines.multi_select_success') + helpHtml('intro.lines.multi_' + (context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch'));
76026             reveal(box, rightClickString);
76027             context.map().on('move.intro drawn.intro', function () {
76028               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
76029               var box = pad(twelfthAvenue, padding, context);
76030               reveal(box, rightClickString, {
76031                 duration: 0
76032               });
76033             });
76034             context.ui().editMenu().on('toggled.intro', function (open) {
76035               if (!open) return;
76036               timeout(function () {
76037                 var ids = context.selectedIDs();
76038
76039                 if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
76040                   var node = selectMenuItem(context, 'delete').node();
76041                   if (!node) return;
76042                   continueTo(multiDelete);
76043                 } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
76044                   return continueTo(multiSelect);
76045                 } else {
76046                   return continueTo(didSplit);
76047                 }
76048               }, 300); // after edit menu visible
76049             });
76050             context.history().on('change.intro', function () {
76051               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
76052                 return continueTo(rightClickIntersection);
76053               }
76054             });
76055
76056             function continueTo(nextStep) {
76057               context.map().on('move.intro drawn.intro', null);
76058               context.ui().editMenu().on('toggled.intro', null);
76059               context.history().on('change.intro', null);
76060               nextStep();
76061             }
76062           }
76063
76064           function multiDelete() {
76065             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
76066               return continueTo(rightClickIntersection);
76067             }
76068
76069             var node = selectMenuItem(context, 'delete').node();
76070             if (!node) return continueTo(multiRightClick);
76071             reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
76072               padding: 50
76073             });
76074             context.map().on('move.intro drawn.intro', function () {
76075               reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
76076                 duration: 0,
76077                 padding: 50
76078               });
76079             });
76080             context.on('exit.intro', function () {
76081               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
76082                 return continueTo(multiSelect); // left select mode but roads still exist
76083               }
76084             });
76085             context.history().on('change.intro', function () {
76086               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
76087                 continueTo(retryDelete); // changed something but roads still exist
76088               } else {
76089                 continueTo(play);
76090               }
76091             });
76092
76093             function continueTo(nextStep) {
76094               context.map().on('move.intro drawn.intro', null);
76095               context.on('exit.intro', null);
76096               context.history().on('change.intro', null);
76097               nextStep();
76098             }
76099           }
76100
76101           function retryDelete() {
76102             context.enter(modeBrowse(context));
76103             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
76104             var box = pad(twelfthAvenue, padding, context);
76105             reveal(box, helpHtml('intro.lines.retry_delete'), {
76106               buttonText: _t.html('intro.ok'),
76107               buttonCallback: function buttonCallback() {
76108                 continueTo(multiSelect);
76109               }
76110             });
76111
76112             function continueTo(nextStep) {
76113               nextStep();
76114             }
76115           }
76116
76117           function play() {
76118             dispatch.call('done');
76119             reveal('.ideditor', helpHtml('intro.lines.play', {
76120               next: _t('intro.buildings.title')
76121             }), {
76122               tooltipBox: '.intro-nav-wrap .chapter-building',
76123               buttonText: _t.html('intro.ok'),
76124               buttonCallback: function buttonCallback() {
76125                 reveal('.ideditor');
76126               }
76127             });
76128           }
76129
76130           chapter.enter = function () {
76131             addLine();
76132           };
76133
76134           chapter.exit = function () {
76135             timeouts.forEach(window.clearTimeout);
76136             select(window).on('pointerdown.intro mousedown.intro', null, true);
76137             context.on('enter.intro exit.intro', null);
76138             context.map().on('move.intro drawn.intro', null);
76139             context.history().on('change.intro', null);
76140             context.container().select('.inspector-wrap').on('wheel.intro', null);
76141             context.container().select('.preset-list-button').on('click.intro', null);
76142           };
76143
76144           chapter.restart = function () {
76145             chapter.exit();
76146             chapter.enter();
76147           };
76148
76149           return utilRebind(chapter, dispatch, 'on');
76150         }
76151
76152         function uiIntroBuilding(context, reveal) {
76153           var dispatch = dispatch$8('done');
76154           var house = [-85.62815, 41.95638];
76155           var tank = [-85.62732, 41.95347];
76156           var buildingCatetory = _mainPresetIndex.item('category-building');
76157           var housePreset = _mainPresetIndex.item('building/house');
76158           var tankPreset = _mainPresetIndex.item('man_made/storage_tank');
76159           var timeouts = [];
76160           var _houseID = null;
76161           var _tankID = null;
76162           var chapter = {
76163             title: 'intro.buildings.title'
76164           };
76165
76166           function timeout(f, t) {
76167             timeouts.push(window.setTimeout(f, t));
76168           }
76169
76170           function eventCancel(d3_event) {
76171             d3_event.stopPropagation();
76172             d3_event.preventDefault();
76173           }
76174
76175           function revealHouse(center, text, options) {
76176             var padding = 160 * Math.pow(2, context.map().zoom() - 20);
76177             var box = pad(center, padding, context);
76178             reveal(box, text, options);
76179           }
76180
76181           function revealTank(center, text, options) {
76182             var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
76183             var box = pad(center, padding, context);
76184             reveal(box, text, options);
76185           }
76186
76187           function addHouse() {
76188             context.enter(modeBrowse(context));
76189             context.history().reset('initial');
76190             _houseID = null;
76191             var msec = transitionTime(house, context.map().center());
76192
76193             if (msec) {
76194               reveal(null, null, {
76195                 duration: 0
76196               });
76197             }
76198
76199             context.map().centerZoomEase(house, 19, msec);
76200             timeout(function () {
76201               var tooltip = reveal('button.add-area', helpHtml('intro.buildings.add_building'));
76202               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-buildings');
76203               context.on('enter.intro', function (mode) {
76204                 if (mode.id !== 'add-area') return;
76205                 continueTo(startHouse);
76206               });
76207             }, msec + 100);
76208
76209             function continueTo(nextStep) {
76210               context.on('enter.intro', null);
76211               nextStep();
76212             }
76213           }
76214
76215           function startHouse() {
76216             if (context.mode().id !== 'add-area') {
76217               return continueTo(addHouse);
76218             }
76219
76220             _houseID = null;
76221             context.map().zoomEase(20, 500);
76222             timeout(function () {
76223               var startString = helpHtml('intro.buildings.start_building') + helpHtml('intro.buildings.building_corner_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
76224               revealHouse(house, startString);
76225               context.map().on('move.intro drawn.intro', function () {
76226                 revealHouse(house, startString, {
76227                   duration: 0
76228                 });
76229               });
76230               context.on('enter.intro', function (mode) {
76231                 if (mode.id !== 'draw-area') return chapter.restart();
76232                 continueTo(continueHouse);
76233               });
76234             }, 550); // after easing
76235
76236             function continueTo(nextStep) {
76237               context.map().on('move.intro drawn.intro', null);
76238               context.on('enter.intro', null);
76239               nextStep();
76240             }
76241           }
76242
76243           function continueHouse() {
76244             if (context.mode().id !== 'draw-area') {
76245               return continueTo(addHouse);
76246             }
76247
76248             _houseID = null;
76249             var continueString = helpHtml('intro.buildings.continue_building') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_building');
76250             revealHouse(house, continueString);
76251             context.map().on('move.intro drawn.intro', function () {
76252               revealHouse(house, continueString, {
76253                 duration: 0
76254               });
76255             });
76256             context.on('enter.intro', function (mode) {
76257               if (mode.id === 'draw-area') {
76258                 return;
76259               } else if (mode.id === 'select') {
76260                 var graph = context.graph();
76261                 var way = context.entity(context.selectedIDs()[0]);
76262                 var nodes = graph.childNodes(way);
76263                 var points = utilArrayUniq(nodes).map(function (n) {
76264                   return context.projection(n.loc);
76265                 });
76266
76267                 if (isMostlySquare(points)) {
76268                   _houseID = way.id;
76269                   return continueTo(chooseCategoryBuilding);
76270                 } else {
76271                   return continueTo(retryHouse);
76272                 }
76273               } else {
76274                 return chapter.restart();
76275               }
76276             });
76277
76278             function continueTo(nextStep) {
76279               context.map().on('move.intro drawn.intro', null);
76280               context.on('enter.intro', null);
76281               nextStep();
76282             }
76283           }
76284
76285           function retryHouse() {
76286             var onClick = function onClick() {
76287               continueTo(addHouse);
76288             };
76289
76290             revealHouse(house, helpHtml('intro.buildings.retry_building'), {
76291               buttonText: _t.html('intro.ok'),
76292               buttonCallback: onClick
76293             });
76294             context.map().on('move.intro drawn.intro', function () {
76295               revealHouse(house, helpHtml('intro.buildings.retry_building'), {
76296                 duration: 0,
76297                 buttonText: _t.html('intro.ok'),
76298                 buttonCallback: onClick
76299               });
76300             });
76301
76302             function continueTo(nextStep) {
76303               context.map().on('move.intro drawn.intro', null);
76304               nextStep();
76305             }
76306           }
76307
76308           function chooseCategoryBuilding() {
76309             if (!_houseID || !context.hasEntity(_houseID)) {
76310               return addHouse();
76311             }
76312
76313             var ids = context.selectedIDs();
76314
76315             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
76316               context.enter(modeSelect(context, [_houseID]));
76317             } // disallow scrolling
76318
76319
76320             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
76321             timeout(function () {
76322               // reset pane, in case user somehow happened to change it..
76323               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
76324               var button = context.container().select('.preset-category-building .preset-list-button');
76325               reveal(button.node(), helpHtml('intro.buildings.choose_category_building', {
76326                 category: buildingCatetory.name()
76327               }));
76328               button.on('click.intro', function () {
76329                 button.on('click.intro', null);
76330                 continueTo(choosePresetHouse);
76331               });
76332             }, 400); // after preset list pane visible..
76333
76334             context.on('enter.intro', function (mode) {
76335               if (!_houseID || !context.hasEntity(_houseID)) {
76336                 return continueTo(addHouse);
76337               }
76338
76339               var ids = context.selectedIDs();
76340
76341               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
76342                 return continueTo(chooseCategoryBuilding);
76343               }
76344             });
76345
76346             function continueTo(nextStep) {
76347               context.container().select('.inspector-wrap').on('wheel.intro', null);
76348               context.container().select('.preset-list-button').on('click.intro', null);
76349               context.on('enter.intro', null);
76350               nextStep();
76351             }
76352           }
76353
76354           function choosePresetHouse() {
76355             if (!_houseID || !context.hasEntity(_houseID)) {
76356               return addHouse();
76357             }
76358
76359             var ids = context.selectedIDs();
76360
76361             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
76362               context.enter(modeSelect(context, [_houseID]));
76363             } // disallow scrolling
76364
76365
76366             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
76367             timeout(function () {
76368               // reset pane, in case user somehow happened to change it..
76369               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
76370               var button = context.container().select('.preset-building-house .preset-list-button');
76371               reveal(button.node(), helpHtml('intro.buildings.choose_preset_house', {
76372                 preset: housePreset.name()
76373               }), {
76374                 duration: 300
76375               });
76376               button.on('click.intro', function () {
76377                 button.on('click.intro', null);
76378                 continueTo(closeEditorHouse);
76379               });
76380             }, 400); // after preset list pane visible..
76381
76382             context.on('enter.intro', function (mode) {
76383               if (!_houseID || !context.hasEntity(_houseID)) {
76384                 return continueTo(addHouse);
76385               }
76386
76387               var ids = context.selectedIDs();
76388
76389               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
76390                 return continueTo(chooseCategoryBuilding);
76391               }
76392             });
76393
76394             function continueTo(nextStep) {
76395               context.container().select('.inspector-wrap').on('wheel.intro', null);
76396               context.container().select('.preset-list-button').on('click.intro', null);
76397               context.on('enter.intro', null);
76398               nextStep();
76399             }
76400           }
76401
76402           function closeEditorHouse() {
76403             if (!_houseID || !context.hasEntity(_houseID)) {
76404               return addHouse();
76405             }
76406
76407             var ids = context.selectedIDs();
76408
76409             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
76410               context.enter(modeSelect(context, [_houseID]));
76411             }
76412
76413             context.history().checkpoint('hasHouse');
76414             context.on('exit.intro', function () {
76415               continueTo(rightClickHouse);
76416             });
76417             timeout(function () {
76418               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
76419                 button: icon('#iD-icon-close', 'inline')
76420               }));
76421             }, 500);
76422
76423             function continueTo(nextStep) {
76424               context.on('exit.intro', null);
76425               nextStep();
76426             }
76427           }
76428
76429           function rightClickHouse() {
76430             if (!_houseID) return chapter.restart();
76431             context.enter(modeBrowse(context));
76432             context.history().reset('hasHouse');
76433             var zoom = context.map().zoom();
76434
76435             if (zoom < 20) {
76436               zoom = 20;
76437             }
76438
76439             context.map().centerZoomEase(house, zoom, 500);
76440             context.on('enter.intro', function (mode) {
76441               if (mode.id !== 'select') return;
76442               var ids = context.selectedIDs();
76443               if (ids.length !== 1 || ids[0] !== _houseID) return;
76444               timeout(function () {
76445                 var node = selectMenuItem(context, 'orthogonalize').node();
76446                 if (!node) return;
76447                 continueTo(clickSquare);
76448               }, 50); // after menu visible
76449             });
76450             context.map().on('move.intro drawn.intro', function () {
76451               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_building' : 'edit_menu_building_touch'));
76452               revealHouse(house, rightclickString, {
76453                 duration: 0
76454               });
76455             });
76456             context.history().on('change.intro', function () {
76457               continueTo(rightClickHouse);
76458             });
76459
76460             function continueTo(nextStep) {
76461               context.on('enter.intro', null);
76462               context.map().on('move.intro drawn.intro', null);
76463               context.history().on('change.intro', null);
76464               nextStep();
76465             }
76466           }
76467
76468           function clickSquare() {
76469             if (!_houseID) return chapter.restart();
76470             var entity = context.hasEntity(_houseID);
76471             if (!entity) return continueTo(rightClickHouse);
76472             var node = selectMenuItem(context, 'orthogonalize').node();
76473
76474             if (!node) {
76475               return continueTo(rightClickHouse);
76476             }
76477
76478             var wasChanged = false;
76479             reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
76480               padding: 50
76481             });
76482             context.on('enter.intro', function (mode) {
76483               if (mode.id === 'browse') {
76484                 continueTo(rightClickHouse);
76485               } else if (mode.id === 'move' || mode.id === 'rotate') {
76486                 continueTo(retryClickSquare);
76487               }
76488             });
76489             context.map().on('move.intro', function () {
76490               var node = selectMenuItem(context, 'orthogonalize').node();
76491
76492               if (!wasChanged && !node) {
76493                 return continueTo(rightClickHouse);
76494               }
76495
76496               reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
76497                 duration: 0,
76498                 padding: 50
76499               });
76500             });
76501             context.history().on('change.intro', function () {
76502               wasChanged = true;
76503               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
76504
76505               timeout(function () {
76506                 if (context.history().undoAnnotation() === _t('operations.orthogonalize.annotation.feature', {
76507                   n: 1
76508                 })) {
76509                   continueTo(doneSquare);
76510                 } else {
76511                   continueTo(retryClickSquare);
76512                 }
76513               }, 500); // after transitioned actions
76514             });
76515
76516             function continueTo(nextStep) {
76517               context.on('enter.intro', null);
76518               context.map().on('move.intro', null);
76519               context.history().on('change.intro', null);
76520               nextStep();
76521             }
76522           }
76523
76524           function retryClickSquare() {
76525             context.enter(modeBrowse(context));
76526             revealHouse(house, helpHtml('intro.buildings.retry_square'), {
76527               buttonText: _t.html('intro.ok'),
76528               buttonCallback: function buttonCallback() {
76529                 continueTo(rightClickHouse);
76530               }
76531             });
76532
76533             function continueTo(nextStep) {
76534               nextStep();
76535             }
76536           }
76537
76538           function doneSquare() {
76539             context.history().checkpoint('doneSquare');
76540             revealHouse(house, helpHtml('intro.buildings.done_square'), {
76541               buttonText: _t.html('intro.ok'),
76542               buttonCallback: function buttonCallback() {
76543                 continueTo(addTank);
76544               }
76545             });
76546
76547             function continueTo(nextStep) {
76548               nextStep();
76549             }
76550           }
76551
76552           function addTank() {
76553             context.enter(modeBrowse(context));
76554             context.history().reset('doneSquare');
76555             _tankID = null;
76556             var msec = transitionTime(tank, context.map().center());
76557
76558             if (msec) {
76559               reveal(null, null, {
76560                 duration: 0
76561               });
76562             }
76563
76564             context.map().centerZoomEase(tank, 19.5, msec);
76565             timeout(function () {
76566               reveal('button.add-area', helpHtml('intro.buildings.add_tank'));
76567               context.on('enter.intro', function (mode) {
76568                 if (mode.id !== 'add-area') return;
76569                 continueTo(startTank);
76570               });
76571             }, msec + 100);
76572
76573             function continueTo(nextStep) {
76574               context.on('enter.intro', null);
76575               nextStep();
76576             }
76577           }
76578
76579           function startTank() {
76580             if (context.mode().id !== 'add-area') {
76581               return continueTo(addTank);
76582             }
76583
76584             _tankID = null;
76585             timeout(function () {
76586               var startString = helpHtml('intro.buildings.start_tank') + helpHtml('intro.buildings.tank_edge_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
76587               revealTank(tank, startString);
76588               context.map().on('move.intro drawn.intro', function () {
76589                 revealTank(tank, startString, {
76590                   duration: 0
76591                 });
76592               });
76593               context.on('enter.intro', function (mode) {
76594                 if (mode.id !== 'draw-area') return chapter.restart();
76595                 continueTo(continueTank);
76596               });
76597             }, 550); // after easing
76598
76599             function continueTo(nextStep) {
76600               context.map().on('move.intro drawn.intro', null);
76601               context.on('enter.intro', null);
76602               nextStep();
76603             }
76604           }
76605
76606           function continueTank() {
76607             if (context.mode().id !== 'draw-area') {
76608               return continueTo(addTank);
76609             }
76610
76611             _tankID = null;
76612             var continueString = helpHtml('intro.buildings.continue_tank') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_tank');
76613             revealTank(tank, continueString);
76614             context.map().on('move.intro drawn.intro', function () {
76615               revealTank(tank, continueString, {
76616                 duration: 0
76617               });
76618             });
76619             context.on('enter.intro', function (mode) {
76620               if (mode.id === 'draw-area') {
76621                 return;
76622               } else if (mode.id === 'select') {
76623                 _tankID = context.selectedIDs()[0];
76624                 return continueTo(searchPresetTank);
76625               } else {
76626                 return continueTo(addTank);
76627               }
76628             });
76629
76630             function continueTo(nextStep) {
76631               context.map().on('move.intro drawn.intro', null);
76632               context.on('enter.intro', null);
76633               nextStep();
76634             }
76635           }
76636
76637           function searchPresetTank() {
76638             if (!_tankID || !context.hasEntity(_tankID)) {
76639               return addTank();
76640             }
76641
76642             var ids = context.selectedIDs();
76643
76644             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
76645               context.enter(modeSelect(context, [_tankID]));
76646             } // disallow scrolling
76647
76648
76649             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
76650             timeout(function () {
76651               // reset pane, in case user somehow happened to change it..
76652               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
76653               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
76654               reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
76655                 preset: tankPreset.name()
76656               }));
76657             }, 400); // after preset list pane visible..
76658
76659             context.on('enter.intro', function (mode) {
76660               if (!_tankID || !context.hasEntity(_tankID)) {
76661                 return continueTo(addTank);
76662               }
76663
76664               var ids = context.selectedIDs();
76665
76666               if (mode.id !== 'select' || !ids.length || ids[0] !== _tankID) {
76667                 // keep the user's area selected..
76668                 context.enter(modeSelect(context, [_tankID])); // reset pane, in case user somehow happened to change it..
76669
76670                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
76671
76672                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
76673                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
76674                 reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
76675                   preset: tankPreset.name()
76676                 }));
76677                 context.history().on('change.intro', null);
76678               }
76679             });
76680
76681             function checkPresetSearch() {
76682               var first = context.container().select('.preset-list-item:first-child');
76683
76684               if (first.classed('preset-man_made-storage_tank')) {
76685                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.buildings.choose_tank', {
76686                   preset: tankPreset.name()
76687                 }), {
76688                   duration: 300
76689                 });
76690                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
76691                 context.history().on('change.intro', function () {
76692                   continueTo(closeEditorTank);
76693                 });
76694               }
76695             }
76696
76697             function continueTo(nextStep) {
76698               context.container().select('.inspector-wrap').on('wheel.intro', null);
76699               context.on('enter.intro', null);
76700               context.history().on('change.intro', null);
76701               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
76702               nextStep();
76703             }
76704           }
76705
76706           function closeEditorTank() {
76707             if (!_tankID || !context.hasEntity(_tankID)) {
76708               return addTank();
76709             }
76710
76711             var ids = context.selectedIDs();
76712
76713             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
76714               context.enter(modeSelect(context, [_tankID]));
76715             }
76716
76717             context.history().checkpoint('hasTank');
76718             context.on('exit.intro', function () {
76719               continueTo(rightClickTank);
76720             });
76721             timeout(function () {
76722               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
76723                 button: icon('#iD-icon-close', 'inline')
76724               }));
76725             }, 500);
76726
76727             function continueTo(nextStep) {
76728               context.on('exit.intro', null);
76729               nextStep();
76730             }
76731           }
76732
76733           function rightClickTank() {
76734             if (!_tankID) return continueTo(addTank);
76735             context.enter(modeBrowse(context));
76736             context.history().reset('hasTank');
76737             context.map().centerEase(tank, 500);
76738             timeout(function () {
76739               context.on('enter.intro', function (mode) {
76740                 if (mode.id !== 'select') return;
76741                 var ids = context.selectedIDs();
76742                 if (ids.length !== 1 || ids[0] !== _tankID) return;
76743                 timeout(function () {
76744                   var node = selectMenuItem(context, 'circularize').node();
76745                   if (!node) return;
76746                   continueTo(clickCircle);
76747                 }, 50); // after menu visible
76748               });
76749               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_tank' : 'edit_menu_tank_touch'));
76750               revealTank(tank, rightclickString);
76751               context.map().on('move.intro drawn.intro', function () {
76752                 revealTank(tank, rightclickString, {
76753                   duration: 0
76754                 });
76755               });
76756               context.history().on('change.intro', function () {
76757                 continueTo(rightClickTank);
76758               });
76759             }, 600);
76760
76761             function continueTo(nextStep) {
76762               context.on('enter.intro', null);
76763               context.map().on('move.intro drawn.intro', null);
76764               context.history().on('change.intro', null);
76765               nextStep();
76766             }
76767           }
76768
76769           function clickCircle() {
76770             if (!_tankID) return chapter.restart();
76771             var entity = context.hasEntity(_tankID);
76772             if (!entity) return continueTo(rightClickTank);
76773             var node = selectMenuItem(context, 'circularize').node();
76774
76775             if (!node) {
76776               return continueTo(rightClickTank);
76777             }
76778
76779             var wasChanged = false;
76780             reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
76781               padding: 50
76782             });
76783             context.on('enter.intro', function (mode) {
76784               if (mode.id === 'browse') {
76785                 continueTo(rightClickTank);
76786               } else if (mode.id === 'move' || mode.id === 'rotate') {
76787                 continueTo(retryClickCircle);
76788               }
76789             });
76790             context.map().on('move.intro', function () {
76791               var node = selectMenuItem(context, 'circularize').node();
76792
76793               if (!wasChanged && !node) {
76794                 return continueTo(rightClickTank);
76795               }
76796
76797               reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
76798                 duration: 0,
76799                 padding: 50
76800               });
76801             });
76802             context.history().on('change.intro', function () {
76803               wasChanged = true;
76804               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
76805
76806               timeout(function () {
76807                 if (context.history().undoAnnotation() === _t('operations.circularize.annotation.feature', {
76808                   n: 1
76809                 })) {
76810                   continueTo(play);
76811                 } else {
76812                   continueTo(retryClickCircle);
76813                 }
76814               }, 500); // after transitioned actions
76815             });
76816
76817             function continueTo(nextStep) {
76818               context.on('enter.intro', null);
76819               context.map().on('move.intro', null);
76820               context.history().on('change.intro', null);
76821               nextStep();
76822             }
76823           }
76824
76825           function retryClickCircle() {
76826             context.enter(modeBrowse(context));
76827             revealTank(tank, helpHtml('intro.buildings.retry_circle'), {
76828               buttonText: _t.html('intro.ok'),
76829               buttonCallback: function buttonCallback() {
76830                 continueTo(rightClickTank);
76831               }
76832             });
76833
76834             function continueTo(nextStep) {
76835               nextStep();
76836             }
76837           }
76838
76839           function play() {
76840             dispatch.call('done');
76841             reveal('.ideditor', helpHtml('intro.buildings.play', {
76842               next: _t('intro.startediting.title')
76843             }), {
76844               tooltipBox: '.intro-nav-wrap .chapter-startEditing',
76845               buttonText: _t.html('intro.ok'),
76846               buttonCallback: function buttonCallback() {
76847                 reveal('.ideditor');
76848               }
76849             });
76850           }
76851
76852           chapter.enter = function () {
76853             addHouse();
76854           };
76855
76856           chapter.exit = function () {
76857             timeouts.forEach(window.clearTimeout);
76858             context.on('enter.intro exit.intro', null);
76859             context.map().on('move.intro drawn.intro', null);
76860             context.history().on('change.intro', null);
76861             context.container().select('.inspector-wrap').on('wheel.intro', null);
76862             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
76863             context.container().select('.more-fields .combobox-input').on('click.intro', null);
76864           };
76865
76866           chapter.restart = function () {
76867             chapter.exit();
76868             chapter.enter();
76869           };
76870
76871           return utilRebind(chapter, dispatch, 'on');
76872         }
76873
76874         function uiIntroStartEditing(context, reveal) {
76875           var dispatch = dispatch$8('done', 'startEditing');
76876           var modalSelection = select(null);
76877           var chapter = {
76878             title: 'intro.startediting.title'
76879           };
76880
76881           function showHelp() {
76882             reveal('.map-control.help-control', helpHtml('intro.startediting.help'), {
76883               buttonText: _t.html('intro.ok'),
76884               buttonCallback: function buttonCallback() {
76885                 shortcuts();
76886               }
76887             });
76888           }
76889
76890           function shortcuts() {
76891             reveal('.map-control.help-control', helpHtml('intro.startediting.shortcuts'), {
76892               buttonText: _t.html('intro.ok'),
76893               buttonCallback: function buttonCallback() {
76894                 showSave();
76895               }
76896             });
76897           }
76898
76899           function showSave() {
76900             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
76901
76902             reveal('.top-toolbar button.save', helpHtml('intro.startediting.save'), {
76903               buttonText: _t.html('intro.ok'),
76904               buttonCallback: function buttonCallback() {
76905                 showStart();
76906               }
76907             });
76908           }
76909
76910           function showStart() {
76911             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
76912
76913             modalSelection = uiModal(context.container());
76914             modalSelection.select('.modal').attr('class', 'modal-splash modal');
76915             modalSelection.selectAll('.close').remove();
76916             var startbutton = modalSelection.select('.content').attr('class', 'fillL').append('button').attr('class', 'modal-section huge-modal-button').on('click', function () {
76917               modalSelection.remove();
76918             });
76919             startbutton.append('svg').attr('class', 'illustration').append('use').attr('xlink:href', '#iD-logo-walkthrough');
76920             startbutton.append('h2').html(_t.html('intro.startediting.start'));
76921             dispatch.call('startEditing');
76922           }
76923
76924           chapter.enter = function () {
76925             showHelp();
76926           };
76927
76928           chapter.exit = function () {
76929             modalSelection.remove();
76930             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
76931           };
76932
76933           return utilRebind(chapter, dispatch, 'on');
76934         }
76935
76936         var chapterUi = {
76937           welcome: uiIntroWelcome,
76938           navigation: uiIntroNavigation,
76939           point: uiIntroPoint,
76940           area: uiIntroArea,
76941           line: uiIntroLine,
76942           building: uiIntroBuilding,
76943           startEditing: uiIntroStartEditing
76944         };
76945         var chapterFlow = ['welcome', 'navigation', 'point', 'area', 'line', 'building', 'startEditing'];
76946         function uiIntro(context) {
76947           var INTRO_IMAGERY = 'EsriWorldImageryClarity';
76948           var _introGraph = {};
76949
76950           var _currChapter;
76951
76952           function intro(selection) {
76953             _mainFileFetcher.get('intro_graph').then(function (dataIntroGraph) {
76954               // create entities for intro graph and localize names
76955               for (var id in dataIntroGraph) {
76956                 if (!_introGraph[id]) {
76957                   _introGraph[id] = osmEntity(localize(dataIntroGraph[id]));
76958                 }
76959               }
76960
76961               selection.call(startIntro);
76962             })["catch"](function () {
76963               /* ignore */
76964             });
76965           }
76966
76967           function startIntro(selection) {
76968             context.enter(modeBrowse(context)); // Save current map state
76969
76970             var osm = context.connection();
76971             var history = context.history().toJSON();
76972             var hash = window.location.hash;
76973             var center = context.map().center();
76974             var zoom = context.map().zoom();
76975             var background = context.background().baseLayerSource();
76976             var overlays = context.background().overlayLayerSources();
76977             var opacity = context.container().selectAll('.main-map .layer-background').style('opacity');
76978             var caches = osm && osm.caches();
76979             var baseEntities = context.history().graph().base().entities; // Show sidebar and disable the sidebar resizing button
76980             // (this needs to be before `context.inIntro(true)`)
76981
76982             context.ui().sidebar.expand();
76983             context.container().selectAll('button.sidebar-toggle').classed('disabled', true); // Block saving
76984
76985             context.inIntro(true); // Load semi-real data used in intro
76986
76987             if (osm) {
76988               osm.toggle(false).reset();
76989             }
76990
76991             context.history().reset();
76992             context.history().merge(Object.values(coreGraph().load(_introGraph).entities));
76993             context.history().checkpoint('initial'); // Setup imagery
76994
76995             var imagery = context.background().findSource(INTRO_IMAGERY);
76996
76997             if (imagery) {
76998               context.background().baseLayerSource(imagery);
76999             } else {
77000               context.background().bing();
77001             }
77002
77003             overlays.forEach(function (d) {
77004               return context.background().toggleOverlayLayer(d);
77005             }); // Setup data layers (only OSM)
77006
77007             var layers = context.layers();
77008             layers.all().forEach(function (item) {
77009               // if the layer has the function `enabled`
77010               if (typeof item.layer.enabled === 'function') {
77011                 item.layer.enabled(item.id === 'osm');
77012               }
77013             });
77014             context.container().selectAll('.main-map .layer-background').style('opacity', 1);
77015             var curtain = uiCurtain(context.container().node());
77016             selection.call(curtain); // Store that the user started the walkthrough..
77017
77018             corePreferences('walkthrough_started', 'yes'); // Restore previous walkthrough progress..
77019
77020             var storedProgress = corePreferences('walkthrough_progress') || '';
77021             var progress = storedProgress.split(';').filter(Boolean);
77022             var chapters = chapterFlow.map(function (chapter, i) {
77023               var s = chapterUi[chapter](context, curtain.reveal).on('done', function () {
77024                 buttons.filter(function (d) {
77025                   return d.title === s.title;
77026                 }).classed('finished', true);
77027
77028                 if (i < chapterFlow.length - 1) {
77029                   var next = chapterFlow[i + 1];
77030                   context.container().select("button.chapter-".concat(next)).classed('next', true);
77031                 } // Store walkthrough progress..
77032
77033
77034                 progress.push(chapter);
77035                 corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';'));
77036               });
77037               return s;
77038             });
77039             chapters[chapters.length - 1].on('startEditing', function () {
77040               // Store walkthrough progress..
77041               progress.push('startEditing');
77042               corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';')); // Store if walkthrough is completed..
77043
77044               var incomplete = utilArrayDifference(chapterFlow, progress);
77045
77046               if (!incomplete.length) {
77047                 corePreferences('walkthrough_completed', 'yes');
77048               }
77049
77050               curtain.remove();
77051               navwrap.remove();
77052               context.container().selectAll('.main-map .layer-background').style('opacity', opacity);
77053               context.container().selectAll('button.sidebar-toggle').classed('disabled', false);
77054
77055               if (osm) {
77056                 osm.toggle(true).reset().caches(caches);
77057               }
77058
77059               context.history().reset().merge(Object.values(baseEntities));
77060               context.background().baseLayerSource(background);
77061               overlays.forEach(function (d) {
77062                 return context.background().toggleOverlayLayer(d);
77063               });
77064
77065               if (history) {
77066                 context.history().fromJSON(history, false);
77067               }
77068
77069               context.map().centerZoom(center, zoom);
77070               window.location.replace(hash);
77071               context.inIntro(false);
77072             });
77073             var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
77074             navwrap.append('svg').attr('class', 'intro-nav-wrap-logo').append('use').attr('xlink:href', '#iD-logo-walkthrough');
77075             var buttonwrap = navwrap.append('div').attr('class', 'joined').selectAll('button.chapter');
77076             var buttons = buttonwrap.data(chapters).enter().append('button').attr('class', function (d, i) {
77077               return "chapter chapter-".concat(chapterFlow[i]);
77078             }).on('click', enterChapter);
77079             buttons.append('span').html(function (d) {
77080               return _t.html(d.title);
77081             });
77082             buttons.append('span').attr('class', 'status').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
77083             enterChapter(null, chapters[0]);
77084
77085             function enterChapter(d3_event, newChapter) {
77086               if (_currChapter) {
77087                 _currChapter.exit();
77088               }
77089
77090               context.enter(modeBrowse(context));
77091               _currChapter = newChapter;
77092
77093               _currChapter.enter();
77094
77095               buttons.classed('next', false).classed('active', function (d) {
77096                 return d.title === _currChapter.title;
77097               });
77098             }
77099           }
77100
77101           return intro;
77102         }
77103
77104         function uiIssuesInfo(context) {
77105           var warningsItem = {
77106             id: 'warnings',
77107             count: 0,
77108             iconID: 'iD-icon-alert',
77109             descriptionID: 'issues.warnings_and_errors'
77110           };
77111           var resolvedItem = {
77112             id: 'resolved',
77113             count: 0,
77114             iconID: 'iD-icon-apply',
77115             descriptionID: 'issues.user_resolved_issues'
77116           };
77117
77118           function update(selection) {
77119             var shownItems = [];
77120             var liveIssues = context.validator().getIssues({
77121               what: corePreferences('validate-what') || 'edited',
77122               where: corePreferences('validate-where') || 'all'
77123             });
77124
77125             if (liveIssues.length) {
77126               warningsItem.count = liveIssues.length;
77127               shownItems.push(warningsItem);
77128             }
77129
77130             if (corePreferences('validate-what') === 'all') {
77131               var resolvedIssues = context.validator().getResolvedIssues();
77132
77133               if (resolvedIssues.length) {
77134                 resolvedItem.count = resolvedIssues.length;
77135                 shownItems.push(resolvedItem);
77136               }
77137             }
77138
77139             var chips = selection.selectAll('.chip').data(shownItems, function (d) {
77140               return d.id;
77141             });
77142             chips.exit().remove();
77143             var enter = chips.enter().append('a').attr('class', function (d) {
77144               return 'chip ' + d.id + '-count';
77145             }).attr('href', '#').each(function (d) {
77146               var chipSelection = select(this);
77147               var tooltipBehavior = uiTooltip().placement('top').title(_t.html(d.descriptionID));
77148               chipSelection.call(tooltipBehavior).on('click', function (d3_event) {
77149                 d3_event.preventDefault();
77150                 tooltipBehavior.hide(select(this)); // open the Issues pane
77151
77152                 context.ui().togglePanes(context.container().select('.map-panes .issues-pane'));
77153               });
77154               chipSelection.call(svgIcon('#' + d.iconID));
77155             });
77156             enter.append('span').attr('class', 'count');
77157             enter.merge(chips).selectAll('span.count').html(function (d) {
77158               return d.count.toString();
77159             });
77160           }
77161
77162           return function (selection) {
77163             update(selection);
77164             context.validator().on('validated.infobox', function () {
77165               update(selection);
77166             });
77167           };
77168         }
77169
77170         function uiMapInMap(context) {
77171           function mapInMap(selection) {
77172             var backgroundLayer = rendererTileLayer(context);
77173             var overlayLayers = {};
77174             var projection = geoRawMercator();
77175             var dataLayer = svgData(projection, context).showLabels(false);
77176             var debugLayer = svgDebug(projection, context);
77177             var zoom = d3_zoom().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on('start', zoomStarted).on('zoom', zoomed).on('end', zoomEnded);
77178             var wrap = select(null);
77179             var tiles = select(null);
77180             var viewport = select(null);
77181             var _isTransformed = false;
77182             var _isHidden = true;
77183             var _skipEvents = false;
77184             var _gesture = null;
77185             var _zDiff = 6; // by default, minimap renders at (main zoom - 6)
77186
77187             var _dMini; // dimensions of minimap
77188
77189
77190             var _cMini; // center pixel of minimap
77191
77192
77193             var _tStart; // transform at start of gesture
77194
77195
77196             var _tCurr; // transform at most recent event
77197
77198
77199             var _timeoutID;
77200
77201             function zoomStarted() {
77202               if (_skipEvents) return;
77203               _tStart = _tCurr = projection.transform();
77204               _gesture = null;
77205             }
77206
77207             function zoomed(d3_event) {
77208               if (_skipEvents) return;
77209               var x = d3_event.transform.x;
77210               var y = d3_event.transform.y;
77211               var k = d3_event.transform.k;
77212               var isZooming = k !== _tStart.k;
77213               var isPanning = x !== _tStart.x || y !== _tStart.y;
77214
77215               if (!isZooming && !isPanning) {
77216                 return; // no change
77217               } // lock in either zooming or panning, don't allow both in minimap.
77218
77219
77220               if (!_gesture) {
77221                 _gesture = isZooming ? 'zoom' : 'pan';
77222               }
77223
77224               var tMini = projection.transform();
77225               var tX, tY, scale;
77226
77227               if (_gesture === 'zoom') {
77228                 scale = k / tMini.k;
77229                 tX = (_cMini[0] / scale - _cMini[0]) * scale;
77230                 tY = (_cMini[1] / scale - _cMini[1]) * scale;
77231               } else {
77232                 k = tMini.k;
77233                 scale = 1;
77234                 tX = x - tMini.x;
77235                 tY = y - tMini.y;
77236               }
77237
77238               utilSetTransform(tiles, tX, tY, scale);
77239               utilSetTransform(viewport, 0, 0, scale);
77240               _isTransformed = true;
77241               _tCurr = identity$2.translate(x, y).scale(k);
77242               var zMain = geoScaleToZoom(context.projection.scale());
77243               var zMini = geoScaleToZoom(k);
77244               _zDiff = zMain - zMini;
77245               queueRedraw();
77246             }
77247
77248             function zoomEnded() {
77249               if (_skipEvents) return;
77250               if (_gesture !== 'pan') return;
77251               updateProjection();
77252               _gesture = null;
77253               context.map().center(projection.invert(_cMini)); // recenter main map..
77254             }
77255
77256             function updateProjection() {
77257               var loc = context.map().center();
77258               var tMain = context.projection.transform();
77259               var zMain = geoScaleToZoom(tMain.k);
77260               var zMini = Math.max(zMain - _zDiff, 0.5);
77261               var kMini = geoZoomToScale(zMini);
77262               projection.translate([tMain.x, tMain.y]).scale(kMini);
77263               var point = projection(loc);
77264               var mouse = _gesture === 'pan' ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
77265               var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
77266               var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
77267               projection.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
77268               _tCurr = projection.transform();
77269
77270               if (_isTransformed) {
77271                 utilSetTransform(tiles, 0, 0);
77272                 utilSetTransform(viewport, 0, 0);
77273                 _isTransformed = false;
77274               }
77275
77276               zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
77277               _skipEvents = true;
77278               wrap.call(zoom.transform, _tCurr);
77279               _skipEvents = false;
77280             }
77281
77282             function redraw() {
77283               clearTimeout(_timeoutID);
77284               if (_isHidden) return;
77285               updateProjection();
77286               var zMini = geoScaleToZoom(projection.scale()); // setup tile container
77287
77288               tiles = wrap.selectAll('.map-in-map-tiles').data([0]);
77289               tiles = tiles.enter().append('div').attr('class', 'map-in-map-tiles').merge(tiles); // redraw background
77290
77291               backgroundLayer.source(context.background().baseLayerSource()).projection(projection).dimensions(_dMini);
77292               var background = tiles.selectAll('.map-in-map-background').data([0]);
77293               background.enter().append('div').attr('class', 'map-in-map-background').merge(background).call(backgroundLayer); // redraw overlay
77294
77295               var overlaySources = context.background().overlayLayerSources();
77296               var activeOverlayLayers = [];
77297
77298               for (var i = 0; i < overlaySources.length; i++) {
77299                 if (overlaySources[i].validZoom(zMini)) {
77300                   if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
77301                   activeOverlayLayers.push(overlayLayers[i].source(overlaySources[i]).projection(projection).dimensions(_dMini));
77302                 }
77303               }
77304
77305               var overlay = tiles.selectAll('.map-in-map-overlay').data([0]);
77306               overlay = overlay.enter().append('div').attr('class', 'map-in-map-overlay').merge(overlay);
77307               var overlays = overlay.selectAll('div').data(activeOverlayLayers, function (d) {
77308                 return d.source().name();
77309               });
77310               overlays.exit().remove();
77311               overlays = overlays.enter().append('div').merge(overlays).each(function (layer) {
77312                 select(this).call(layer);
77313               });
77314               var dataLayers = tiles.selectAll('.map-in-map-data').data([0]);
77315               dataLayers.exit().remove();
77316               dataLayers = dataLayers.enter().append('svg').attr('class', 'map-in-map-data').merge(dataLayers).call(dataLayer).call(debugLayer); // redraw viewport bounding box
77317
77318               if (_gesture !== 'pan') {
77319                 var getPath = d3_geoPath(projection);
77320                 var bbox = {
77321                   type: 'Polygon',
77322                   coordinates: [context.map().extent().polygon()]
77323                 };
77324                 viewport = wrap.selectAll('.map-in-map-viewport').data([0]);
77325                 viewport = viewport.enter().append('svg').attr('class', 'map-in-map-viewport').merge(viewport);
77326                 var path = viewport.selectAll('.map-in-map-bbox').data([bbox]);
77327                 path.enter().append('path').attr('class', 'map-in-map-bbox').merge(path).attr('d', getPath).classed('thick', function (d) {
77328                   return getPath.area(d) < 30;
77329                 });
77330               }
77331             }
77332
77333             function queueRedraw() {
77334               clearTimeout(_timeoutID);
77335               _timeoutID = setTimeout(function () {
77336                 redraw();
77337               }, 750);
77338             }
77339
77340             function toggle(d3_event) {
77341               if (d3_event) d3_event.preventDefault();
77342               _isHidden = !_isHidden;
77343               context.container().select('.minimap-toggle-item').classed('active', !_isHidden).select('input').property('checked', !_isHidden);
77344
77345               if (_isHidden) {
77346                 wrap.style('display', 'block').style('opacity', '1').transition().duration(200).style('opacity', '0').on('end', function () {
77347                   selection.selectAll('.map-in-map').style('display', 'none');
77348                 });
77349               } else {
77350                 wrap.style('display', 'block').style('opacity', '0').transition().duration(200).style('opacity', '1').on('end', function () {
77351                   redraw();
77352                 });
77353               }
77354             }
77355
77356             uiMapInMap.toggle = toggle;
77357             wrap = selection.selectAll('.map-in-map').data([0]);
77358             wrap = wrap.enter().append('div').attr('class', 'map-in-map').style('display', _isHidden ? 'none' : 'block').call(zoom).on('dblclick.zoom', null).merge(wrap); // reflow warning: Hardcode dimensions - currently can't resize it anyway..
77359
77360             _dMini = [200, 150]; //utilGetDimensions(wrap);
77361
77362             _cMini = geoVecScale(_dMini, 0.5);
77363             context.map().on('drawn.map-in-map', function (drawn) {
77364               if (drawn.full === true) {
77365                 redraw();
77366               }
77367             });
77368             redraw();
77369             context.keybinding().on(_t('background.minimap.key'), toggle);
77370           }
77371
77372           return mapInMap;
77373         }
77374
77375         function uiNotice(context) {
77376           return function (selection) {
77377             var div = selection.append('div').attr('class', 'notice');
77378             var button = div.append('button').attr('class', 'zoom-to notice fillD').on('click', function () {
77379               context.map().zoomEase(context.minEditableZoom());
77380             }).on('wheel', function (d3_event) {
77381               // let wheel events pass through #4482
77382               var e2 = new WheelEvent(d3_event.type, d3_event);
77383               context.surface().node().dispatchEvent(e2);
77384             });
77385             button.call(svgIcon('#iD-icon-plus', 'pre-text')).append('span').attr('class', 'label').html(_t.html('zoom_in_edit'));
77386
77387             function disableTooHigh() {
77388               var canEdit = context.map().zoom() >= context.minEditableZoom();
77389               div.style('display', canEdit ? 'none' : 'block');
77390             }
77391
77392             context.map().on('move.notice', debounce(disableTooHigh, 500));
77393             disableTooHigh();
77394           };
77395         }
77396
77397         function uiPhotoviewer(context) {
77398           var dispatch = dispatch$8('resize');
77399
77400           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
77401
77402           function photoviewer(selection) {
77403             selection.append('button').attr('class', 'thumb-hide').on('click', function () {
77404               if (services.streetside) {
77405                 services.streetside.hideViewer(context);
77406               }
77407
77408               if (services.mapillary) {
77409                 services.mapillary.hideViewer(context);
77410               }
77411
77412               if (services.openstreetcam) {
77413                 services.openstreetcam.hideViewer(context);
77414               }
77415             }).append('div').call(svgIcon('#iD-icon-close'));
77416
77417             function preventDefault(d3_event) {
77418               d3_event.preventDefault();
77419             }
77420
77421             selection.append('button').attr('class', 'resize-handle-xy').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch, {
77422               resizeOnX: true,
77423               resizeOnY: true
77424             }));
77425             selection.append('button').attr('class', 'resize-handle-x').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch, {
77426               resizeOnX: true
77427             }));
77428             selection.append('button').attr('class', 'resize-handle-y').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch, {
77429               resizeOnY: true
77430             }));
77431
77432             function buildResizeListener(target, eventName, dispatch, options) {
77433               var resizeOnX = !!options.resizeOnX;
77434               var resizeOnY = !!options.resizeOnY;
77435               var minHeight = options.minHeight || 240;
77436               var minWidth = options.minWidth || 320;
77437               var pointerId;
77438               var startX;
77439               var startY;
77440               var startWidth;
77441               var startHeight;
77442
77443               function startResize(d3_event) {
77444                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
77445                 d3_event.preventDefault();
77446                 d3_event.stopPropagation();
77447                 var mapSize = context.map().dimensions();
77448
77449                 if (resizeOnX) {
77450                   var maxWidth = mapSize[0];
77451                   var newWidth = clamp(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
77452                   target.style('width', newWidth + 'px');
77453                 }
77454
77455                 if (resizeOnY) {
77456                   var maxHeight = mapSize[1] - 90; // preserve space at top/bottom of map
77457
77458                   var newHeight = clamp(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
77459                   target.style('height', newHeight + 'px');
77460                 }
77461
77462                 dispatch.call(eventName, target, utilGetDimensions(target, true));
77463               }
77464
77465               function clamp(num, min, max) {
77466                 return Math.max(min, Math.min(num, max));
77467               }
77468
77469               function stopResize(d3_event) {
77470                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
77471                 d3_event.preventDefault();
77472                 d3_event.stopPropagation(); // remove all the listeners we added
77473
77474                 select(window).on('.' + eventName, null);
77475               }
77476
77477               return function initResize(d3_event) {
77478                 d3_event.preventDefault();
77479                 d3_event.stopPropagation();
77480                 pointerId = d3_event.pointerId || 'mouse';
77481                 startX = d3_event.clientX;
77482                 startY = d3_event.clientY;
77483                 var targetRect = target.node().getBoundingClientRect();
77484                 startWidth = targetRect.width;
77485                 startHeight = targetRect.height;
77486                 select(window).on(_pointerPrefix + 'move.' + eventName, startResize, false).on(_pointerPrefix + 'up.' + eventName, stopResize, false);
77487
77488                 if (_pointerPrefix === 'pointer') {
77489                   select(window).on('pointercancel.' + eventName, stopResize, false);
77490                 }
77491               };
77492             }
77493           }
77494
77495           photoviewer.onMapResize = function () {
77496             var photoviewer = context.container().select('.photoviewer');
77497             var content = context.container().select('.main-content');
77498             var mapDimensions = utilGetDimensions(content, true); // shrink photo viewer if it is too big
77499             // (-90 preserves space at top and bottom of map used by menus)
77500
77501             var photoDimensions = utilGetDimensions(photoviewer, true);
77502
77503             if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
77504               var setPhotoDimensions = [Math.min(photoDimensions[0], mapDimensions[0]), Math.min(photoDimensions[1], mapDimensions[1] - 90)];
77505               photoviewer.style('width', setPhotoDimensions[0] + 'px').style('height', setPhotoDimensions[1] + 'px');
77506               dispatch.call('resize', photoviewer, setPhotoDimensions);
77507             }
77508           };
77509
77510           return utilRebind(photoviewer, dispatch, 'on');
77511         }
77512
77513         function uiRestore(context) {
77514           return function (selection) {
77515             if (!context.history().hasRestorableChanges()) return;
77516             var modalSelection = uiModal(selection, true);
77517             modalSelection.select('.modal').attr('class', 'modal fillL');
77518             var introModal = modalSelection.select('.content');
77519             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('restore.heading'));
77520             introModal.append('div').attr('class', 'modal-section').append('p').html(_t.html('restore.description'));
77521             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
77522             var restore = buttonWrap.append('button').attr('class', 'restore').on('click', function () {
77523               context.history().restore();
77524               modalSelection.remove();
77525             });
77526             restore.append('svg').attr('class', 'logo logo-restore').append('use').attr('xlink:href', '#iD-logo-restore');
77527             restore.append('div').html(_t.html('restore.restore'));
77528             var reset = buttonWrap.append('button').attr('class', 'reset').on('click', function () {
77529               context.history().clearSaved();
77530               modalSelection.remove();
77531             });
77532             reset.append('svg').attr('class', 'logo logo-reset').append('use').attr('xlink:href', '#iD-logo-reset');
77533             reset.append('div').html(_t.html('restore.reset'));
77534             restore.node().focus();
77535           };
77536         }
77537
77538         function uiScale(context) {
77539           var projection = context.projection,
77540               isImperial = !_mainLocalizer.usesMetric(),
77541               maxLength = 180,
77542               tickHeight = 8;
77543
77544           function scaleDefs(loc1, loc2) {
77545             var lat = (loc2[1] + loc1[1]) / 2,
77546                 conversion = isImperial ? 3.28084 : 1,
77547                 dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
77548                 scale = {
77549               dist: 0,
77550               px: 0,
77551               text: ''
77552             },
77553                 buckets,
77554                 i,
77555                 val,
77556                 dLon;
77557
77558             if (isImperial) {
77559               buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
77560             } else {
77561               buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
77562             } // determine a user-friendly endpoint for the scale
77563
77564
77565             for (i = 0; i < buckets.length; i++) {
77566               val = buckets[i];
77567
77568               if (dist >= val) {
77569                 scale.dist = Math.floor(dist / val) * val;
77570                 break;
77571               } else {
77572                 scale.dist = +dist.toFixed(2);
77573               }
77574             }
77575
77576             dLon = geoMetersToLon(scale.dist / conversion, lat);
77577             scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
77578             scale.text = displayLength(scale.dist / conversion, isImperial);
77579             return scale;
77580           }
77581
77582           function update(selection) {
77583             // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
77584             var dims = context.map().dimensions(),
77585                 loc1 = projection.invert([0, dims[1]]),
77586                 loc2 = projection.invert([maxLength, dims[1]]),
77587                 scale = scaleDefs(loc1, loc2);
77588             selection.select('.scale-path').attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
77589             selection.select('.scale-text').style(_mainLocalizer.textDirection() === 'ltr' ? 'left' : 'right', scale.px + 16 + 'px').html(scale.text);
77590           }
77591
77592           return function (selection) {
77593             function switchUnits() {
77594               isImperial = !isImperial;
77595               selection.call(update);
77596             }
77597
77598             var scalegroup = selection.append('svg').attr('class', 'scale').on('click', switchUnits).append('g').attr('transform', 'translate(10,11)');
77599             scalegroup.append('path').attr('class', 'scale-path');
77600             selection.append('div').attr('class', 'scale-text');
77601             selection.call(update);
77602             context.map().on('move.scale', function () {
77603               update(selection);
77604             });
77605           };
77606         }
77607
77608         function uiShortcuts(context) {
77609           var detected = utilDetect();
77610           var _activeTab = 0;
77611
77612           var _modalSelection;
77613
77614           var _selection = select(null);
77615
77616           var _dataShortcuts;
77617
77618           function shortcutsModal(_modalSelection) {
77619             _modalSelection.select('.modal').classed('modal-shortcuts', true);
77620
77621             var content = _modalSelection.select('.content');
77622
77623             content.append('div').attr('class', 'modal-section').append('h3').html(_t.html('shortcuts.title'));
77624             _mainFileFetcher.get('shortcuts').then(function (data) {
77625               _dataShortcuts = data;
77626               content.call(render);
77627             })["catch"](function () {
77628               /* ignore */
77629             });
77630           }
77631
77632           function render(selection) {
77633             if (!_dataShortcuts) return;
77634             var wrapper = selection.selectAll('.wrapper').data([0]);
77635             var wrapperEnter = wrapper.enter().append('div').attr('class', 'wrapper modal-section');
77636             var tabsBar = wrapperEnter.append('div').attr('class', 'tabs-bar');
77637             var shortcutsList = wrapperEnter.append('div').attr('class', 'shortcuts-list');
77638             wrapper = wrapper.merge(wrapperEnter);
77639             var tabs = tabsBar.selectAll('.tab').data(_dataShortcuts);
77640             var tabsEnter = tabs.enter().append('a').attr('class', 'tab').attr('href', '#').on('click', function (d3_event, d) {
77641               d3_event.preventDefault();
77642
77643               var i = _dataShortcuts.indexOf(d);
77644
77645               _activeTab = i;
77646               render(selection);
77647             });
77648             tabsEnter.append('span').html(function (d) {
77649               return _t.html(d.text);
77650             }); // Update
77651
77652             wrapper.selectAll('.tab').classed('active', function (d, i) {
77653               return i === _activeTab;
77654             });
77655             var shortcuts = shortcutsList.selectAll('.shortcut-tab').data(_dataShortcuts);
77656             var shortcutsEnter = shortcuts.enter().append('div').attr('class', function (d) {
77657               return 'shortcut-tab shortcut-tab-' + d.tab;
77658             });
77659             var columnsEnter = shortcutsEnter.selectAll('.shortcut-column').data(function (d) {
77660               return d.columns;
77661             }).enter().append('table').attr('class', 'shortcut-column');
77662             var rowsEnter = columnsEnter.selectAll('.shortcut-row').data(function (d) {
77663               return d.rows;
77664             }).enter().append('tr').attr('class', 'shortcut-row');
77665             var sectionRows = rowsEnter.filter(function (d) {
77666               return !d.shortcuts;
77667             });
77668             sectionRows.append('td');
77669             sectionRows.append('td').attr('class', 'shortcut-section').append('h3').html(function (d) {
77670               return _t.html(d.text);
77671             });
77672             var shortcutRows = rowsEnter.filter(function (d) {
77673               return d.shortcuts;
77674             });
77675             var shortcutKeys = shortcutRows.append('td').attr('class', 'shortcut-keys');
77676             var modifierKeys = shortcutKeys.filter(function (d) {
77677               return d.modifiers;
77678             });
77679             modifierKeys.selectAll('kbd.modifier').data(function (d) {
77680               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
77681                 return ['⌘'];
77682               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
77683                 return [];
77684               } else {
77685                 return d.modifiers;
77686               }
77687             }).enter().each(function () {
77688               var selection = select(this);
77689               selection.append('kbd').attr('class', 'modifier').html(function (d) {
77690                 return uiCmd.display(d);
77691               });
77692               selection.append('span').html('+');
77693             });
77694             shortcutKeys.selectAll('kbd.shortcut').data(function (d) {
77695               var arr = d.shortcuts;
77696
77697               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
77698                 arr = ['Y'];
77699               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
77700                 arr = ['F11'];
77701               } // replace translations
77702
77703
77704               arr = arr.map(function (s) {
77705                 return uiCmd.display(s.indexOf('.') !== -1 ? _t(s) : s);
77706               });
77707               return utilArrayUniq(arr).map(function (s) {
77708                 return {
77709                   shortcut: s,
77710                   separator: d.separator,
77711                   suffix: d.suffix
77712                 };
77713               });
77714             }).enter().each(function (d, i, nodes) {
77715               var selection = select(this);
77716               var click = d.shortcut.toLowerCase().match(/(.*).click/);
77717
77718               if (click && click[1]) {
77719                 // replace "left_click", "right_click" with mouse icon
77720                 selection.call(svgIcon('#iD-walkthrough-mouse-' + click[1], 'operation'));
77721               } else if (d.shortcut.toLowerCase() === 'long-press') {
77722                 selection.call(svgIcon('#iD-walkthrough-longpress', 'longpress operation'));
77723               } else if (d.shortcut.toLowerCase() === 'tap') {
77724                 selection.call(svgIcon('#iD-walkthrough-tap', 'tap operation'));
77725               } else {
77726                 selection.append('kbd').attr('class', 'shortcut').html(function (d) {
77727                   return d.shortcut;
77728                 });
77729               }
77730
77731               if (i < nodes.length - 1) {
77732                 selection.append('span').html(d.separator || "\xA0" + _t.html('shortcuts.or') + "\xA0");
77733               } else if (i === nodes.length - 1 && d.suffix) {
77734                 selection.append('span').html(d.suffix);
77735               }
77736             });
77737             shortcutKeys.filter(function (d) {
77738               return d.gesture;
77739             }).each(function () {
77740               var selection = select(this);
77741               selection.append('span').html('+');
77742               selection.append('span').attr('class', 'gesture').html(function (d) {
77743                 return _t.html(d.gesture);
77744               });
77745             });
77746             shortcutRows.append('td').attr('class', 'shortcut-desc').html(function (d) {
77747               return d.text ? _t.html(d.text) : "\xA0";
77748             }); // Update
77749
77750             wrapper.selectAll('.shortcut-tab').style('display', function (d, i) {
77751               return i === _activeTab ? 'flex' : 'none';
77752             });
77753           }
77754
77755           return function (selection, show) {
77756             _selection = selection;
77757
77758             if (show) {
77759               _modalSelection = uiModal(selection);
77760
77761               _modalSelection.call(shortcutsModal);
77762             } else {
77763               context.keybinding().on([_t('shortcuts.toggle.key'), '?'], function () {
77764                 if (context.container().selectAll('.modal-shortcuts').size()) {
77765                   // already showing
77766                   if (_modalSelection) {
77767                     _modalSelection.close();
77768
77769                     _modalSelection = null;
77770                   }
77771                 } else {
77772                   _modalSelection = uiModal(_selection);
77773
77774                   _modalSelection.call(shortcutsModal);
77775                 }
77776               });
77777             }
77778           };
77779         }
77780
77781         function uiDataHeader() {
77782           var _datum;
77783
77784           function dataHeader(selection) {
77785             var header = selection.selectAll('.data-header').data(_datum ? [_datum] : [], function (d) {
77786               return d.__featurehash__;
77787             });
77788             header.exit().remove();
77789             var headerEnter = header.enter().append('div').attr('class', 'data-header');
77790             var iconEnter = headerEnter.append('div').attr('class', 'data-header-icon');
77791             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-data', 'note-fill'));
77792             headerEnter.append('div').attr('class', 'data-header-label').html(_t.html('map_data.layers.custom.title'));
77793           }
77794
77795           dataHeader.datum = function (val) {
77796             if (!arguments.length) return _datum;
77797             _datum = val;
77798             return this;
77799           };
77800
77801           return dataHeader;
77802         }
77803
77804         // It is keyed on the `value` of the entry. Data should be an array of objects like:
77805         //   [{
77806         //       value:   'string value',  // required
77807         //       display: 'label html'     // optional
77808         //       title:   'hover text'     // optional
77809         //       terms:   ['search terms'] // optional
77810         //   }, ...]
77811
77812         var _comboHideTimerID;
77813
77814         function uiCombobox(context, klass) {
77815           var dispatch = dispatch$8('accept', 'cancel');
77816           var container = context.container();
77817           var _suggestions = [];
77818           var _data = [];
77819           var _fetched = {};
77820           var _selected = null;
77821           var _canAutocomplete = true;
77822           var _caseSensitive = false;
77823           var _cancelFetch = false;
77824           var _minItems = 2;
77825           var _tDown = 0;
77826
77827           var _mouseEnterHandler, _mouseLeaveHandler;
77828
77829           var _fetcher = function _fetcher(val, cb) {
77830             cb(_data.filter(function (d) {
77831               var terms = d.terms || [];
77832               terms.push(d.value);
77833               return terms.some(function (term) {
77834                 return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
77835               });
77836             }));
77837           };
77838
77839           var combobox = function combobox(input, attachTo) {
77840             if (!input || input.empty()) return;
77841             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 () {
77842               var parent = this.parentNode;
77843               var sibling = this.nextSibling;
77844               select(parent).selectAll('.combobox-caret').filter(function (d) {
77845                 return d === input.node();
77846               }).data([input.node()]).enter().insert('div', function () {
77847                 return sibling;
77848               }).attr('class', 'combobox-caret').on('mousedown.combo-caret', function (d3_event) {
77849                 d3_event.preventDefault(); // don't steal focus from input
77850
77851                 input.node().focus(); // focus the input as if it was clicked
77852
77853                 mousedown(d3_event);
77854               }).on('mouseup.combo-caret', function (d3_event) {
77855                 d3_event.preventDefault(); // don't steal focus from input
77856
77857                 mouseup(d3_event);
77858               });
77859             });
77860
77861             function mousedown(d3_event) {
77862               if (d3_event.button !== 0) return; // left click only
77863
77864               _tDown = +new Date(); // clear selection
77865
77866               var start = input.property('selectionStart');
77867               var end = input.property('selectionEnd');
77868
77869               if (start !== end) {
77870                 var val = utilGetSetValue(input);
77871                 input.node().setSelectionRange(val.length, val.length);
77872                 return;
77873               }
77874
77875               input.on('mouseup.combo-input', mouseup);
77876             }
77877
77878             function mouseup(d3_event) {
77879               input.on('mouseup.combo-input', null);
77880               if (d3_event.button !== 0) return; // left click only
77881
77882               if (input.node() !== document.activeElement) return; // exit if this input is not focused
77883
77884               var start = input.property('selectionStart');
77885               var end = input.property('selectionEnd');
77886               if (start !== end) return; // exit if user is selecting
77887               // not showing or showing for a different field - try to show it.
77888
77889               var combo = container.selectAll('.combobox');
77890
77891               if (combo.empty() || combo.datum() !== input.node()) {
77892                 var tOrig = _tDown;
77893                 window.setTimeout(function () {
77894                   if (tOrig !== _tDown) return; // exit if user double clicked
77895
77896                   fetchComboData('', function () {
77897                     show();
77898                     render();
77899                   });
77900                 }, 250);
77901               } else {
77902                 hide();
77903               }
77904             }
77905
77906             function focus() {
77907               fetchComboData(''); // prefetch values (may warm taginfo cache)
77908             }
77909
77910             function blur() {
77911               _comboHideTimerID = window.setTimeout(hide, 75);
77912             }
77913
77914             function show() {
77915               hide(); // remove any existing
77916
77917               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) {
77918                 // prevent moving focus out of the input field
77919                 d3_event.preventDefault();
77920               });
77921               container.on('scroll.combo-scroll', render, true);
77922             }
77923
77924             function hide() {
77925               if (_comboHideTimerID) {
77926                 window.clearTimeout(_comboHideTimerID);
77927                 _comboHideTimerID = undefined;
77928               }
77929
77930               container.selectAll('.combobox').remove();
77931               container.on('scroll.combo-scroll', null);
77932             }
77933
77934             function keydown(d3_event) {
77935               var shown = !container.selectAll('.combobox').empty();
77936               var tagName = input.node() ? input.node().tagName.toLowerCase() : '';
77937
77938               switch (d3_event.keyCode) {
77939                 case 8: // ⌫ Backspace
77940
77941                 case 46:
77942                   // ⌦ Delete
77943                   d3_event.stopPropagation();
77944                   _selected = null;
77945                   render();
77946                   input.on('input.combo-input', function () {
77947                     var start = input.property('selectionStart');
77948                     input.node().setSelectionRange(start, start);
77949                     input.on('input.combo-input', change);
77950                   });
77951                   break;
77952
77953                 case 9:
77954                   // ⇥ Tab
77955                   accept();
77956                   break;
77957
77958                 case 13:
77959                   // ↩ Return
77960                   d3_event.preventDefault();
77961                   d3_event.stopPropagation();
77962                   break;
77963
77964                 case 38:
77965                   // ↑ Up arrow
77966                   if (tagName === 'textarea' && !shown) return;
77967                   d3_event.preventDefault();
77968
77969                   if (tagName === 'input' && !shown) {
77970                     show();
77971                   }
77972
77973                   nav(-1);
77974                   break;
77975
77976                 case 40:
77977                   // ↓ Down arrow
77978                   if (tagName === 'textarea' && !shown) return;
77979                   d3_event.preventDefault();
77980
77981                   if (tagName === 'input' && !shown) {
77982                     show();
77983                   }
77984
77985                   nav(+1);
77986                   break;
77987               }
77988             }
77989
77990             function keyup(d3_event) {
77991               switch (d3_event.keyCode) {
77992                 case 27:
77993                   // ⎋ Escape
77994                   cancel();
77995                   break;
77996
77997                 case 13:
77998                   // ↩ Return
77999                   accept();
78000                   break;
78001               }
78002             } // Called whenever the input value is changed (e.g. on typing)
78003
78004
78005             function change() {
78006               fetchComboData(value(), function () {
78007                 _selected = null;
78008                 var val = input.property('value');
78009
78010                 if (_suggestions.length) {
78011                   if (input.property('selectionEnd') === val.length) {
78012                     _selected = tryAutocomplete();
78013                   }
78014
78015                   if (!_selected) {
78016                     _selected = val;
78017                   }
78018                 }
78019
78020                 if (val.length) {
78021                   var combo = container.selectAll('.combobox');
78022
78023                   if (combo.empty()) {
78024                     show();
78025                   }
78026                 } else {
78027                   hide();
78028                 }
78029
78030                 render();
78031               });
78032             } // Called when the user presses up/down arrows to navigate the list
78033
78034
78035             function nav(dir) {
78036               if (_suggestions.length) {
78037                 // try to determine previously selected index..
78038                 var index = -1;
78039
78040                 for (var i = 0; i < _suggestions.length; i++) {
78041                   if (_selected && _suggestions[i].value === _selected) {
78042                     index = i;
78043                     break;
78044                   }
78045                 } // pick new _selected
78046
78047
78048                 index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
78049                 _selected = _suggestions[index].value;
78050                 input.property('value', _selected);
78051               }
78052
78053               render();
78054               ensureVisible();
78055             }
78056
78057             function ensureVisible() {
78058               var combo = container.selectAll('.combobox');
78059               if (combo.empty()) return;
78060               var containerRect = container.node().getBoundingClientRect();
78061               var comboRect = combo.node().getBoundingClientRect();
78062
78063               if (comboRect.bottom > containerRect.bottom) {
78064                 var node = attachTo ? attachTo.node() : input.node();
78065                 node.scrollIntoView({
78066                   behavior: 'instant',
78067                   block: 'center'
78068                 });
78069                 render();
78070               } // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move
78071
78072
78073               var selected = combo.selectAll('.combobox-option.selected').node();
78074
78075               if (selected) {
78076                 selected.scrollIntoView({
78077                   behavior: 'smooth',
78078                   block: 'nearest'
78079                 });
78080               }
78081             }
78082
78083             function value() {
78084               var value = input.property('value');
78085               var start = input.property('selectionStart');
78086               var end = input.property('selectionEnd');
78087
78088               if (start && end) {
78089                 value = value.substring(0, start);
78090               }
78091
78092               return value;
78093             }
78094
78095             function fetchComboData(v, cb) {
78096               _cancelFetch = false;
78097
78098               _fetcher.call(input, v, function (results) {
78099                 // already chose a value, don't overwrite or autocomplete it
78100                 if (_cancelFetch) return;
78101                 _suggestions = results;
78102                 results.forEach(function (d) {
78103                   _fetched[d.value] = d;
78104                 });
78105
78106                 if (cb) {
78107                   cb();
78108                 }
78109               });
78110             }
78111
78112             function tryAutocomplete() {
78113               if (!_canAutocomplete) return;
78114               var val = _caseSensitive ? value() : value().toLowerCase();
78115               if (!val) return; // Don't autocomplete if user is typing a number - #4935
78116
78117               if (!isNaN(parseFloat(val)) && isFinite(val)) return;
78118               var bestIndex = -1;
78119
78120               for (var i = 0; i < _suggestions.length; i++) {
78121                 var suggestion = _suggestions[i].value;
78122                 var compare = _caseSensitive ? suggestion : suggestion.toLowerCase(); // if search string matches suggestion exactly, pick it..
78123
78124                 if (compare === val) {
78125                   bestIndex = i;
78126                   break; // otherwise lock in the first result that starts with the search string..
78127                 } else if (bestIndex === -1 && compare.indexOf(val) === 0) {
78128                   bestIndex = i;
78129                 }
78130               }
78131
78132               if (bestIndex !== -1) {
78133                 var bestVal = _suggestions[bestIndex].value;
78134                 input.property('value', bestVal);
78135                 input.node().setSelectionRange(val.length, bestVal.length);
78136                 return bestVal;
78137               }
78138             }
78139
78140             function render() {
78141               if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
78142                 hide();
78143                 return;
78144               }
78145
78146               var shown = !container.selectAll('.combobox').empty();
78147               if (!shown) return;
78148               var combo = container.selectAll('.combobox');
78149               var options = combo.selectAll('.combobox-option').data(_suggestions, function (d) {
78150                 return d.value;
78151               });
78152               options.exit().remove(); // enter/update
78153
78154               options.enter().append('a').attr('class', function (d) {
78155                 return 'combobox-option ' + (d.klass || '');
78156               }).attr('title', function (d) {
78157                 return d.title;
78158               }).html(function (d) {
78159                 return d.display || d.value;
78160               }).on('mouseenter', _mouseEnterHandler).on('mouseleave', _mouseLeaveHandler).merge(options).classed('selected', function (d) {
78161                 return d.value === _selected;
78162               }).on('click.combo-option', accept).order();
78163               var node = attachTo ? attachTo.node() : input.node();
78164               var containerRect = container.node().getBoundingClientRect();
78165               var rect = node.getBoundingClientRect();
78166               combo.style('left', rect.left + 5 - containerRect.left + 'px').style('width', rect.width - 10 + 'px').style('top', rect.height + rect.top - containerRect.top + 'px');
78167             } // Dispatches an 'accept' event
78168             // Then hides the combobox.
78169
78170
78171             function accept(d3_event, d) {
78172               _cancelFetch = true;
78173               var thiz = input.node();
78174
78175               if (d) {
78176                 // user clicked on a suggestion
78177                 utilGetSetValue(input, d.value); // replace field contents
78178
78179                 utilTriggerEvent(input, 'change');
78180               } // clear (and keep) selection
78181
78182
78183               var val = utilGetSetValue(input);
78184               thiz.setSelectionRange(val.length, val.length);
78185               d = _fetched[val];
78186               dispatch.call('accept', thiz, d, val);
78187               hide();
78188             } // Dispatches an 'cancel' event
78189             // Then hides the combobox.
78190
78191
78192             function cancel() {
78193               _cancelFetch = true;
78194               var thiz = input.node(); // clear (and remove) selection, and replace field contents
78195
78196               var val = utilGetSetValue(input);
78197               var start = input.property('selectionStart');
78198               var end = input.property('selectionEnd');
78199               val = val.slice(0, start) + val.slice(end);
78200               utilGetSetValue(input, val);
78201               thiz.setSelectionRange(val.length, val.length);
78202               dispatch.call('cancel', thiz);
78203               hide();
78204             }
78205           };
78206
78207           combobox.canAutocomplete = function (val) {
78208             if (!arguments.length) return _canAutocomplete;
78209             _canAutocomplete = val;
78210             return combobox;
78211           };
78212
78213           combobox.caseSensitive = function (val) {
78214             if (!arguments.length) return _caseSensitive;
78215             _caseSensitive = val;
78216             return combobox;
78217           };
78218
78219           combobox.data = function (val) {
78220             if (!arguments.length) return _data;
78221             _data = val;
78222             return combobox;
78223           };
78224
78225           combobox.fetcher = function (val) {
78226             if (!arguments.length) return _fetcher;
78227             _fetcher = val;
78228             return combobox;
78229           };
78230
78231           combobox.minItems = function (val) {
78232             if (!arguments.length) return _minItems;
78233             _minItems = val;
78234             return combobox;
78235           };
78236
78237           combobox.itemsMouseEnter = function (val) {
78238             if (!arguments.length) return _mouseEnterHandler;
78239             _mouseEnterHandler = val;
78240             return combobox;
78241           };
78242
78243           combobox.itemsMouseLeave = function (val) {
78244             if (!arguments.length) return _mouseLeaveHandler;
78245             _mouseLeaveHandler = val;
78246             return combobox;
78247           };
78248
78249           return utilRebind(combobox, dispatch, 'on');
78250         }
78251
78252         uiCombobox.off = function (input, context) {
78253           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);
78254           context.container().on('scroll.combo-scroll', null);
78255         };
78256
78257         function uiDisclosure(context, key, expandedDefault) {
78258           var dispatch = dispatch$8('toggled');
78259
78260           var _expanded;
78261
78262           var _label = utilFunctor('');
78263
78264           var _updatePreference = true;
78265
78266           var _content = function _content() {};
78267
78268           var disclosure = function disclosure(selection) {
78269             if (_expanded === undefined || _expanded === null) {
78270               // loading _expanded here allows it to be reset by calling `disclosure.expanded(null)`
78271               var preference = corePreferences('disclosure.' + key + '.expanded');
78272               _expanded = preference === null ? !!expandedDefault : preference === 'true';
78273             }
78274
78275             var hideToggle = selection.selectAll('.hide-toggle-' + key).data([0]); // enter
78276
78277             var hideToggleEnter = hideToggle.enter().append('a').attr('href', '#').attr('class', 'hide-toggle hide-toggle-' + key).call(svgIcon('', 'pre-text', 'hide-toggle-icon'));
78278             hideToggleEnter.append('span').attr('class', 'hide-toggle-text'); // update
78279
78280             hideToggle = hideToggleEnter.merge(hideToggle);
78281             hideToggle.on('click', toggle).classed('expanded', _expanded);
78282             hideToggle.selectAll('.hide-toggle-text').html(_label());
78283             hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
78284             var wrap = selection.selectAll('.disclosure-wrap').data([0]); // enter/update
78285
78286             wrap = wrap.enter().append('div').attr('class', 'disclosure-wrap disclosure-wrap-' + key).merge(wrap).classed('hide', !_expanded);
78287
78288             if (_expanded) {
78289               wrap.call(_content);
78290             }
78291
78292             function toggle(d3_event) {
78293               d3_event.preventDefault();
78294               _expanded = !_expanded;
78295
78296               if (_updatePreference) {
78297                 corePreferences('disclosure.' + key + '.expanded', _expanded);
78298               }
78299
78300               hideToggle.classed('expanded', _expanded);
78301               hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
78302               wrap.call(uiToggle(_expanded));
78303
78304               if (_expanded) {
78305                 wrap.call(_content);
78306               }
78307
78308               dispatch.call('toggled', this, _expanded);
78309             }
78310           };
78311
78312           disclosure.label = function (val) {
78313             if (!arguments.length) return _label;
78314             _label = utilFunctor(val);
78315             return disclosure;
78316           };
78317
78318           disclosure.expanded = function (val) {
78319             if (!arguments.length) return _expanded;
78320             _expanded = val;
78321             return disclosure;
78322           };
78323
78324           disclosure.updatePreference = function (val) {
78325             if (!arguments.length) return _updatePreference;
78326             _updatePreference = val;
78327             return disclosure;
78328           };
78329
78330           disclosure.content = function (val) {
78331             if (!arguments.length) return _content;
78332             _content = val;
78333             return disclosure;
78334           };
78335
78336           return utilRebind(disclosure, dispatch, 'on');
78337         }
78338
78339         // Can be labeled and collapsible.
78340
78341         function uiSection(id, context) {
78342           var _classes = utilFunctor('');
78343
78344           var _shouldDisplay;
78345
78346           var _content;
78347
78348           var _disclosure;
78349
78350           var _label;
78351
78352           var _expandedByDefault = utilFunctor(true);
78353
78354           var _disclosureContent;
78355
78356           var _disclosureExpanded;
78357
78358           var _containerSelection = select(null);
78359
78360           var section = {
78361             id: id
78362           };
78363
78364           section.classes = function (val) {
78365             if (!arguments.length) return _classes;
78366             _classes = utilFunctor(val);
78367             return section;
78368           };
78369
78370           section.label = function (val) {
78371             if (!arguments.length) return _label;
78372             _label = utilFunctor(val);
78373             return section;
78374           };
78375
78376           section.expandedByDefault = function (val) {
78377             if (!arguments.length) return _expandedByDefault;
78378             _expandedByDefault = utilFunctor(val);
78379             return section;
78380           };
78381
78382           section.shouldDisplay = function (val) {
78383             if (!arguments.length) return _shouldDisplay;
78384             _shouldDisplay = utilFunctor(val);
78385             return section;
78386           };
78387
78388           section.content = function (val) {
78389             if (!arguments.length) return _content;
78390             _content = val;
78391             return section;
78392           };
78393
78394           section.disclosureContent = function (val) {
78395             if (!arguments.length) return _disclosureContent;
78396             _disclosureContent = val;
78397             return section;
78398           };
78399
78400           section.disclosureExpanded = function (val) {
78401             if (!arguments.length) return _disclosureExpanded;
78402             _disclosureExpanded = val;
78403             return section;
78404           }; // may be called multiple times
78405
78406
78407           section.render = function (selection) {
78408             _containerSelection = selection.selectAll('.section-' + id).data([0]);
78409
78410             var sectionEnter = _containerSelection.enter().append('div').attr('class', 'section section-' + id + ' ' + (_classes && _classes() || ''));
78411
78412             _containerSelection = sectionEnter.merge(_containerSelection);
78413
78414             _containerSelection.call(renderContent);
78415           };
78416
78417           section.reRender = function () {
78418             _containerSelection.call(renderContent);
78419           };
78420
78421           section.selection = function () {
78422             return _containerSelection;
78423           };
78424
78425           section.disclosure = function () {
78426             return _disclosure;
78427           }; // may be called multiple times
78428
78429
78430           function renderContent(selection) {
78431             if (_shouldDisplay) {
78432               var shouldDisplay = _shouldDisplay();
78433
78434               selection.classed('hide', !shouldDisplay);
78435
78436               if (!shouldDisplay) {
78437                 selection.html('');
78438                 return;
78439               }
78440             }
78441
78442             if (_disclosureContent) {
78443               if (!_disclosure) {
78444                 _disclosure = uiDisclosure(context, id.replace(/-/g, '_'), _expandedByDefault()).label(_label || '')
78445                 /*.on('toggled', function(expanded) {
78446                     if (expanded) { selection.node().parentNode.scrollTop += 200; }
78447                 })*/
78448                 .content(_disclosureContent);
78449               }
78450
78451               if (_disclosureExpanded !== undefined) {
78452                 _disclosure.expanded(_disclosureExpanded);
78453
78454                 _disclosureExpanded = undefined;
78455               }
78456
78457               selection.call(_disclosure);
78458               return;
78459             }
78460
78461             if (_content) {
78462               selection.call(_content);
78463             }
78464           }
78465
78466           return section;
78467         }
78468
78469         // {
78470         //   key: 'string',     // required
78471         //   value: 'string'    // optional
78472         // }
78473         //   -or-
78474         // {
78475         //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
78476         // }
78477         //
78478
78479         function uiTagReference(what) {
78480           var wikibase = what.qid ? services.wikidata : services.osmWikibase;
78481           var tagReference = {};
78482
78483           var _button = select(null);
78484
78485           var _body = select(null);
78486
78487           var _loaded;
78488
78489           var _showing;
78490
78491           function load() {
78492             if (!wikibase) return;
78493
78494             _button.classed('tag-reference-loading', true);
78495
78496             wikibase.getDocs(what, gotDocs);
78497           }
78498
78499           function gotDocs(err, docs) {
78500             _body.html('');
78501
78502             if (!docs || !docs.title) {
78503               _body.append('p').attr('class', 'tag-reference-description').html(_t.html('inspector.no_documentation_key'));
78504
78505               done();
78506               return;
78507             }
78508
78509             if (docs.imageURL) {
78510               _body.append('img').attr('class', 'tag-reference-wiki-image').attr('src', docs.imageURL).on('load', function () {
78511                 done();
78512               }).on('error', function () {
78513                 select(this).remove();
78514                 done();
78515               });
78516             } else {
78517               done();
78518             }
78519
78520             _body.append('p').attr('class', 'tag-reference-description').html(docs.description ? _mainLocalizer.htmlForLocalizedText(docs.description, docs.descriptionLocaleCode) : _t.html('inspector.no_documentation_key')).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'));
78521
78522             if (docs.wiki) {
78523               _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').html(_t.html(docs.wiki.text));
78524             } // Add link to info about "good changeset comments" - #2923
78525
78526
78527             if (what.key === 'comment') {
78528               _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').html(_t.html('commit.about_changeset_comments'));
78529             }
78530           }
78531
78532           function done() {
78533             _loaded = true;
78534
78535             _button.classed('tag-reference-loading', false);
78536
78537             _body.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1');
78538
78539             _showing = true;
78540
78541             _button.selectAll('svg.icon use').each(function () {
78542               var iconUse = select(this);
78543
78544               if (iconUse.attr('href') === '#iD-icon-info') {
78545                 iconUse.attr('href', '#iD-icon-info-filled');
78546               }
78547             });
78548           }
78549
78550           function hide() {
78551             _body.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
78552               _body.classed('expanded', false);
78553             });
78554
78555             _showing = false;
78556
78557             _button.selectAll('svg.icon use').each(function () {
78558               var iconUse = select(this);
78559
78560               if (iconUse.attr('href') === '#iD-icon-info-filled') {
78561                 iconUse.attr('href', '#iD-icon-info');
78562               }
78563             });
78564           }
78565
78566           tagReference.button = function (selection, klass, iconName) {
78567             _button = selection.selectAll('.tag-reference-button').data([0]);
78568             _button = _button.enter().append('button').attr('class', 'tag-reference-button ' + (klass || '')).attr('title', _t('icons.information')).call(svgIcon('#iD-icon-' + (iconName || 'inspect'))).merge(_button);
78569
78570             _button.on('click', function (d3_event) {
78571               d3_event.stopPropagation();
78572               d3_event.preventDefault();
78573               this.blur(); // avoid keeping focus on the button - #4641
78574
78575               if (_showing) {
78576                 hide();
78577               } else if (_loaded) {
78578                 done();
78579               } else {
78580                 load();
78581               }
78582             });
78583           };
78584
78585           tagReference.body = function (selection) {
78586             var itemID = what.qid || what.key + '-' + (what.value || '');
78587             _body = selection.selectAll('.tag-reference-body').data([itemID], function (d) {
78588               return d;
78589             });
78590
78591             _body.exit().remove();
78592
78593             _body = _body.enter().append('div').attr('class', 'tag-reference-body').style('max-height', '0').style('opacity', '0').merge(_body);
78594
78595             if (_showing === false) {
78596               hide();
78597             }
78598           };
78599
78600           tagReference.showing = function (val) {
78601             if (!arguments.length) return _showing;
78602             _showing = val;
78603             return tagReference;
78604           };
78605
78606           return tagReference;
78607         }
78608
78609         function uiSectionRawTagEditor(id, context) {
78610           var section = uiSection(id, context).classes('raw-tag-editor').label(function () {
78611             var count = Object.keys(_tags).filter(function (d) {
78612               return d;
78613             }).length;
78614             return _t('inspector.title_count', {
78615               title: _t.html('inspector.tags'),
78616               count: count
78617             });
78618           }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
78619           var taginfo = services.taginfo;
78620           var dispatch = dispatch$8('change');
78621           var availableViews = [{
78622             id: 'list',
78623             icon: '#fas-th-list'
78624           }, {
78625             id: 'text',
78626             icon: '#fas-i-cursor'
78627           }];
78628
78629           var _tagView = corePreferences('raw-tag-editor-view') || 'list'; // 'list, 'text'
78630
78631
78632           var _readOnlyTags = []; // the keys in the order we want them to display
78633
78634           var _orderedKeys = [];
78635           var _showBlank = false;
78636           var _pendingChange = null;
78637
78638           var _state;
78639
78640           var _presets;
78641
78642           var _tags;
78643
78644           var _entityIDs;
78645
78646           var _didInteract = false;
78647
78648           function interacted() {
78649             _didInteract = true;
78650           }
78651
78652           function renderDisclosureContent(wrap) {
78653             // remove deleted keys
78654             _orderedKeys = _orderedKeys.filter(function (key) {
78655               return _tags[key] !== undefined;
78656             }); // When switching to a different entity or changing the state (hover/select)
78657             // reorder the keys alphabetically.
78658             // We trigger this by emptying the `_orderedKeys` array, then it will be rebuilt here.
78659             // Otherwise leave their order alone - #5857, #5927
78660
78661             var all = Object.keys(_tags).sort();
78662             var missingKeys = utilArrayDifference(all, _orderedKeys);
78663
78664             for (var i in missingKeys) {
78665               _orderedKeys.push(missingKeys[i]);
78666             } // assemble row data
78667
78668
78669             var rowData = _orderedKeys.map(function (key, i) {
78670               return {
78671                 index: i,
78672                 key: key,
78673                 value: _tags[key]
78674               };
78675             }); // append blank row last, if necessary
78676
78677
78678             if (!rowData.length || _showBlank) {
78679               _showBlank = false;
78680               rowData.push({
78681                 index: rowData.length,
78682                 key: '',
78683                 value: ''
78684               });
78685             } // View Options
78686
78687
78688             var options = wrap.selectAll('.raw-tag-options').data([0]);
78689             options.exit().remove();
78690             var optionsEnter = options.enter().insert('div', ':first-child').attr('class', 'raw-tag-options');
78691             var optionEnter = optionsEnter.selectAll('.raw-tag-option').data(availableViews, function (d) {
78692               return d.id;
78693             }).enter();
78694             optionEnter.append('button').attr('class', function (d) {
78695               return 'raw-tag-option raw-tag-option-' + d.id + (_tagView === d.id ? ' selected' : '');
78696             }).attr('title', function (d) {
78697               return _t('icons.' + d.id);
78698             }).on('click', function (d3_event, d) {
78699               _tagView = d.id;
78700               corePreferences('raw-tag-editor-view', d.id);
78701               wrap.selectAll('.raw-tag-option').classed('selected', function (datum) {
78702                 return datum === d;
78703               });
78704               wrap.selectAll('.tag-text').classed('hide', d.id !== 'text').each(setTextareaHeight);
78705               wrap.selectAll('.tag-list, .add-row').classed('hide', d.id !== 'list');
78706             }).each(function (d) {
78707               select(this).call(svgIcon(d.icon));
78708             }); // View as Text
78709
78710             var textData = rowsToText(rowData);
78711             var textarea = wrap.selectAll('.tag-text').data([0]);
78712             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);
78713             textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on('input', setTextareaHeight).on('focus', interacted).on('blur', textChanged).on('change', textChanged); // View as List
78714
78715             var list = wrap.selectAll('.tag-list').data([0]);
78716             list = list.enter().append('ul').attr('class', 'tag-list' + (_tagView !== 'list' ? ' hide' : '')).merge(list); // Container for the Add button
78717
78718             var addRowEnter = wrap.selectAll('.add-row').data([0]).enter().append('div').attr('class', 'add-row' + (_tagView !== 'list' ? ' hide' : ''));
78719             addRowEnter.append('button').attr('class', 'add-tag').call(svgIcon('#iD-icon-plus', 'light')).on('click', addTag);
78720             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
78721
78722             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
78723             // Tag list items
78724
78725             var items = list.selectAll('.tag-row').data(rowData, function (d) {
78726               return d.key;
78727             });
78728             items.exit().each(unbind).remove(); // Enter
78729
78730             var itemsEnter = items.enter().append('li').attr('class', 'tag-row').classed('readonly', isReadOnly);
78731             var innerWrap = itemsEnter.append('div').attr('class', 'inner-wrap');
78732             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);
78733             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);
78734             innerWrap.append('button').attr('class', 'form-field-button remove').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete')); // Update
78735
78736             items = items.merge(itemsEnter).sort(function (a, b) {
78737               return a.index - b.index;
78738             });
78739             items.each(function (d) {
78740               var row = select(this);
78741               var key = row.select('input.key'); // propagate bound data
78742
78743               var value = row.select('input.value'); // propagate bound data
78744
78745               if (_entityIDs && taginfo && _state !== 'hover') {
78746                 bindTypeahead(key, value);
78747               }
78748
78749               var referenceOptions = {
78750                 key: d.key
78751               };
78752
78753               if (typeof d.value === 'string') {
78754                 referenceOptions.value = d.value;
78755               }
78756
78757               var reference = uiTagReference(referenceOptions);
78758
78759               if (_state === 'hover') {
78760                 reference.showing(false);
78761               }
78762
78763               row.select('.inner-wrap') // propagate bound data
78764               .call(reference.button);
78765               row.call(reference.body);
78766               row.select('button.remove'); // propagate bound data
78767             });
78768             items.selectAll('input.key').attr('title', function (d) {
78769               return d.key;
78770             }).call(utilGetSetValue, function (d) {
78771               return d.key;
78772             }).attr('readonly', function (d) {
78773               return isReadOnly(d) || typeof d.value !== 'string' || null;
78774             });
78775             items.selectAll('input.value').attr('title', function (d) {
78776               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : d.value;
78777             }).classed('mixed', function (d) {
78778               return Array.isArray(d.value);
78779             }).attr('placeholder', function (d) {
78780               return typeof d.value === 'string' ? null : _t('inspector.multiple_values');
78781             }).call(utilGetSetValue, function (d) {
78782               return typeof d.value === 'string' ? d.value : '';
78783             }).attr('readonly', function (d) {
78784               return isReadOnly(d) || null;
78785             });
78786             items.selectAll('button.remove').on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'down', removeTag); // 'click' fires too late - #5878
78787           }
78788
78789           function isReadOnly(d) {
78790             for (var i = 0; i < _readOnlyTags.length; i++) {
78791               if (d.key.match(_readOnlyTags[i]) !== null) {
78792                 return true;
78793               }
78794             }
78795
78796             return false;
78797           }
78798
78799           function setTextareaHeight() {
78800             if (_tagView !== 'text') return;
78801             var selection = select(this);
78802             var matches = selection.node().value.match(/\n/g);
78803             var lineCount = 2 + Number(matches && matches.length);
78804             var lineHeight = 20;
78805             selection.style('height', lineCount * lineHeight + 'px');
78806           }
78807
78808           function stringify(s) {
78809             return JSON.stringify(s).slice(1, -1); // without leading/trailing "
78810           }
78811
78812           function unstringify(s) {
78813             var leading = '';
78814             var trailing = '';
78815
78816             if (s.length < 1 || s.charAt(0) !== '"') {
78817               leading = '"';
78818             }
78819
78820             if (s.length < 2 || s.charAt(s.length - 1) !== '"' || s.charAt(s.length - 1) === '"' && s.charAt(s.length - 2) === '\\') {
78821               trailing = '"';
78822             }
78823
78824             return JSON.parse(leading + s + trailing);
78825           }
78826
78827           function rowsToText(rows) {
78828             var str = rows.filter(function (row) {
78829               return row.key && row.key.trim() !== '';
78830             }).map(function (row) {
78831               var rawVal = row.value;
78832               if (typeof rawVal !== 'string') rawVal = '*';
78833               var val = rawVal ? stringify(rawVal) : '';
78834               return stringify(row.key) + '=' + val;
78835             }).join('\n');
78836
78837             if (_state !== 'hover' && str.length) {
78838               return str + '\n';
78839             }
78840
78841             return str;
78842           }
78843
78844           function textChanged() {
78845             var newText = this.value.trim();
78846             var newTags = {};
78847             newText.split('\n').forEach(function (row) {
78848               var m = row.match(/^\s*([^=]+)=(.*)$/);
78849
78850               if (m !== null) {
78851                 var k = context.cleanTagKey(unstringify(m[1].trim()));
78852                 var v = context.cleanTagValue(unstringify(m[2].trim()));
78853                 newTags[k] = v;
78854               }
78855             });
78856             var tagDiff = utilTagDiff(_tags, newTags);
78857             if (!tagDiff.length) return;
78858             _pendingChange = _pendingChange || {};
78859             tagDiff.forEach(function (change) {
78860               if (isReadOnly({
78861                 key: change.key
78862               })) return; // skip unchanged multiselection placeholders
78863
78864               if (change.newVal === '*' && typeof change.oldVal !== 'string') return;
78865
78866               if (change.type === '-') {
78867                 _pendingChange[change.key] = undefined;
78868               } else if (change.type === '+') {
78869                 _pendingChange[change.key] = change.newVal || '';
78870               }
78871             });
78872
78873             if (Object.keys(_pendingChange).length === 0) {
78874               _pendingChange = null;
78875               return;
78876             }
78877
78878             scheduleChange();
78879           }
78880
78881           function pushMore(d3_event) {
78882             // if pressing Tab on the last value field with content, add a blank row
78883             if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll('.tag-list li:last-child input.value').node() === this && utilGetSetValue(select(this))) {
78884               addTag();
78885             }
78886           }
78887
78888           function bindTypeahead(key, value) {
78889             if (isReadOnly(key.datum())) return;
78890
78891             if (Array.isArray(value.datum().value)) {
78892               value.call(uiCombobox(context, 'tag-value').minItems(1).fetcher(function (value, callback) {
78893                 var keyString = utilGetSetValue(key);
78894                 if (!_tags[keyString]) return;
78895
78896                 var data = _tags[keyString].filter(Boolean).map(function (tagValue) {
78897                   return {
78898                     value: tagValue,
78899                     title: tagValue
78900                   };
78901                 });
78902
78903                 callback(data);
78904               }));
78905               return;
78906             }
78907
78908             var geometry = context.graph().geometry(_entityIDs[0]);
78909             key.call(uiCombobox(context, 'tag-key').fetcher(function (value, callback) {
78910               taginfo.keys({
78911                 debounce: true,
78912                 geometry: geometry,
78913                 query: value
78914               }, function (err, data) {
78915                 if (!err) {
78916                   var filtered = data.filter(function (d) {
78917                     return _tags[d.value] === undefined;
78918                   });
78919                   callback(sort(value, filtered));
78920                 }
78921               });
78922             }));
78923             value.call(uiCombobox(context, 'tag-value').fetcher(function (value, callback) {
78924               taginfo.values({
78925                 debounce: true,
78926                 key: utilGetSetValue(key),
78927                 geometry: geometry,
78928                 query: value
78929               }, function (err, data) {
78930                 if (!err) callback(sort(value, data));
78931               });
78932             }));
78933
78934             function sort(value, data) {
78935               var sameletter = [];
78936               var other = [];
78937
78938               for (var i = 0; i < data.length; i++) {
78939                 if (data[i].value.substring(0, value.length) === value) {
78940                   sameletter.push(data[i]);
78941                 } else {
78942                   other.push(data[i]);
78943                 }
78944               }
78945
78946               return sameletter.concat(other);
78947             }
78948           }
78949
78950           function unbind() {
78951             var row = select(this);
78952             row.selectAll('input.key').call(uiCombobox.off, context);
78953             row.selectAll('input.value').call(uiCombobox.off, context);
78954           }
78955
78956           function keyChange(d3_event, d) {
78957             if (select(this).attr('readonly')) return;
78958             var kOld = d.key; // exit if we are currently about to delete this row anyway - #6366
78959
78960             if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === undefined) return;
78961             var kNew = context.cleanTagKey(this.value.trim()); // allow no change if the key should be readonly
78962
78963             if (isReadOnly({
78964               key: kNew
78965             })) {
78966               this.value = kOld;
78967               return;
78968             }
78969
78970             if (kNew && kNew !== kOld && _tags[kNew] !== undefined) {
78971               // new key is already in use, switch focus to the existing row
78972               this.value = kOld; // reset the key
78973
78974               section.selection().selectAll('.tag-list input.value').each(function (d) {
78975                 if (d.key === kNew) {
78976                   // send focus to that other value combo instead
78977                   var input = select(this).node();
78978                   input.focus();
78979                   input.select();
78980                 }
78981               });
78982               return;
78983             }
78984
78985             var row = this.parentNode.parentNode;
78986             var inputVal = select(row).selectAll('input.value');
78987             var vNew = context.cleanTagValue(utilGetSetValue(inputVal));
78988             _pendingChange = _pendingChange || {};
78989
78990             if (kOld) {
78991               _pendingChange[kOld] = undefined;
78992             }
78993
78994             _pendingChange[kNew] = vNew; // update the ordered key index so this row doesn't change position
78995
78996             var existingKeyIndex = _orderedKeys.indexOf(kOld);
78997
78998             if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
78999             d.key = kNew; // update datum to avoid exit/enter on tag update
79000
79001             d.value = vNew;
79002             this.value = kNew;
79003             utilGetSetValue(inputVal, vNew);
79004             scheduleChange();
79005           }
79006
79007           function valueChange(d3_event, d) {
79008             if (isReadOnly(d)) return; // exit if this is a multiselection and no value was entered
79009
79010             if (typeof d.value !== 'string' && !this.value) return; // exit if we are currently about to delete this row anyway - #6366
79011
79012             if (_pendingChange && _pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
79013             _pendingChange = _pendingChange || {};
79014             _pendingChange[d.key] = context.cleanTagValue(this.value);
79015             scheduleChange();
79016           }
79017
79018           function removeTag(d3_event, d) {
79019             if (isReadOnly(d)) return;
79020
79021             if (d.key === '') {
79022               // removing the blank row
79023               _showBlank = false;
79024               section.reRender();
79025             } else {
79026               // remove the key from the ordered key index
79027               _orderedKeys = _orderedKeys.filter(function (key) {
79028                 return key !== d.key;
79029               });
79030               _pendingChange = _pendingChange || {};
79031               _pendingChange[d.key] = undefined;
79032               scheduleChange();
79033             }
79034           }
79035
79036           function addTag() {
79037             // Delay render in case this click is blurring an edited combo.
79038             // Without the setTimeout, the `content` render would wipe out the pending tag change.
79039             window.setTimeout(function () {
79040               _showBlank = true;
79041               section.reRender();
79042               section.selection().selectAll('.tag-list li:last-child input.key').node().focus();
79043             }, 20);
79044           }
79045
79046           function scheduleChange() {
79047             // Cache IDs in case the editor is reloaded before the change event is called. - #6028
79048             var entityIDs = _entityIDs; // Delay change in case this change is blurring an edited combo. - #5878
79049
79050             window.setTimeout(function () {
79051               if (!_pendingChange) return;
79052               dispatch.call('change', this, entityIDs, _pendingChange);
79053               _pendingChange = null;
79054             }, 10);
79055           }
79056
79057           section.state = function (val) {
79058             if (!arguments.length) return _state;
79059
79060             if (_state !== val) {
79061               _orderedKeys = [];
79062               _state = val;
79063             }
79064
79065             return section;
79066           };
79067
79068           section.presets = function (val) {
79069             if (!arguments.length) return _presets;
79070             _presets = val;
79071
79072             if (_presets && _presets.length && _presets[0].isFallback()) {
79073               section.disclosureExpanded(true); // don't collapse the disclosure if the mapper used the raw tag editor - #1881
79074             } else if (!_didInteract) {
79075               section.disclosureExpanded(null);
79076             }
79077
79078             return section;
79079           };
79080
79081           section.tags = function (val) {
79082             if (!arguments.length) return _tags;
79083             _tags = val;
79084             return section;
79085           };
79086
79087           section.entityIDs = function (val) {
79088             if (!arguments.length) return _entityIDs;
79089
79090             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
79091               _entityIDs = val;
79092               _orderedKeys = [];
79093             }
79094
79095             return section;
79096           }; // pass an array of regular expressions to test against the tag key
79097
79098
79099           section.readOnlyTags = function (val) {
79100             if (!arguments.length) return _readOnlyTags;
79101             _readOnlyTags = val;
79102             return section;
79103           };
79104
79105           return utilRebind(section, dispatch, 'on');
79106         }
79107
79108         function uiDataEditor(context) {
79109           var dataHeader = uiDataHeader();
79110           var rawTagEditor = uiSectionRawTagEditor('custom-data-tag-editor', context).expandedByDefault(true).readOnlyTags([/./]);
79111
79112           var _datum;
79113
79114           function dataEditor(selection) {
79115             var header = selection.selectAll('.header').data([0]);
79116             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
79117             headerEnter.append('button').attr('class', 'close').on('click', function () {
79118               context.enter(modeBrowse(context));
79119             }).call(svgIcon('#iD-icon-close'));
79120             headerEnter.append('h3').html(_t.html('map_data.title'));
79121             var body = selection.selectAll('.body').data([0]);
79122             body = body.enter().append('div').attr('class', 'body').merge(body);
79123             var editor = body.selectAll('.data-editor').data([0]); // enter/update
79124
79125             editor.enter().append('div').attr('class', 'modal-section data-editor').merge(editor).call(dataHeader.datum(_datum));
79126             var rte = body.selectAll('.raw-tag-editor').data([0]); // enter/update
79127
79128             rte.enter().append('div').attr('class', 'raw-tag-editor data-editor').merge(rte).call(rawTagEditor.tags(_datum && _datum.properties || {}).state('hover').render).selectAll('textarea.tag-text').attr('readonly', true).classed('readonly', true);
79129           }
79130
79131           dataEditor.datum = function (val) {
79132             if (!arguments.length) return _datum;
79133             _datum = val;
79134             return this;
79135           };
79136
79137           return dataEditor;
79138         }
79139
79140         var pair_1 = pair;
79141
79142         function search(input, dims) {
79143           if (!dims) dims = 'NSEW';
79144           if (typeof input !== 'string') return null;
79145           input = input.toUpperCase();
79146           var regex = /^[\s\,]*([NSEW])?\s*([\-|\—|\―]?[0-9.]+)[°º˚]?\s*(?:([0-9.]+)['’′‘]\s*)?(?:([0-9.]+)(?:''|"|”|″)\s*)?([NSEW])?/;
79147           var m = input.match(regex);
79148           if (!m) return null; // no match
79149
79150           var matched = m[0]; // extract dimension.. m[1] = leading, m[5] = trailing
79151
79152           var dim;
79153
79154           if (m[1] && m[5]) {
79155             // if matched both..
79156             dim = m[1]; // keep leading
79157
79158             matched = matched.slice(0, -1); // remove trailing dimension from match
79159           } else {
79160             dim = m[1] || m[5];
79161           } // if unrecognized dimension
79162
79163
79164           if (dim && dims.indexOf(dim) === -1) return null; // extract DMS
79165
79166           var deg = m[2] ? parseFloat(m[2]) : 0;
79167           var min = m[3] ? parseFloat(m[3]) / 60 : 0;
79168           var sec = m[4] ? parseFloat(m[4]) / 3600 : 0;
79169           var sign = deg < 0 ? -1 : 1;
79170           if (dim === 'S' || dim === 'W') sign *= -1;
79171           return {
79172             val: (Math.abs(deg) + min + sec) * sign,
79173             dim: dim,
79174             matched: matched,
79175             remain: input.slice(matched.length)
79176           };
79177         }
79178
79179         function pair(input, dims) {
79180           input = input.trim();
79181           var one = search(input, dims);
79182           if (!one) return null;
79183           input = one.remain.trim();
79184           var two = search(input, dims);
79185           if (!two || two.remain) return null;
79186
79187           if (one.dim) {
79188             return swapdim(one.val, two.val, one.dim);
79189           } else {
79190             return [one.val, two.val];
79191           }
79192         }
79193
79194         function swapdim(a, b, dim) {
79195           if (dim === 'N' || dim === 'S') return [a, b];
79196           if (dim === 'W' || dim === 'E') return [b, a];
79197         }
79198
79199         function uiFeatureList(context) {
79200           var _geocodeResults;
79201
79202           function featureList(selection) {
79203             var header = selection.append('div').attr('class', 'header fillL');
79204             header.append('h3').html(_t.html('inspector.feature_list'));
79205             var searchWrap = selection.append('div').attr('class', 'search-header');
79206             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
79207             var search = searchWrap.append('input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keypress', keypress).on('keydown', keydown).on('input', inputevent);
79208             var listWrap = selection.append('div').attr('class', 'inspector-body');
79209             var list = listWrap.append('div').attr('class', 'feature-list');
79210             context.on('exit.feature-list', clearSearch);
79211             context.map().on('drawn.feature-list', mapDrawn);
79212             context.keybinding().on(uiCmd('⌘F'), focusSearch);
79213
79214             function focusSearch(d3_event) {
79215               var mode = context.mode() && context.mode().id;
79216               if (mode !== 'browse') return;
79217               d3_event.preventDefault();
79218               search.node().focus();
79219             }
79220
79221             function keydown(d3_event) {
79222               if (d3_event.keyCode === 27) {
79223                 // escape
79224                 search.node().blur();
79225               }
79226             }
79227
79228             function keypress(d3_event) {
79229               var q = search.property('value'),
79230                   items = list.selectAll('.feature-list-item');
79231
79232               if (d3_event.keyCode === 13 && // ↩ Return
79233               q.length && items.size()) {
79234                 click(d3_event, items.datum());
79235               }
79236             }
79237
79238             function inputevent() {
79239               _geocodeResults = undefined;
79240               drawList();
79241             }
79242
79243             function clearSearch() {
79244               search.property('value', '');
79245               drawList();
79246             }
79247
79248             function mapDrawn(e) {
79249               if (e.full) {
79250                 drawList();
79251               }
79252             }
79253
79254             function features() {
79255               var result = [];
79256               var graph = context.graph();
79257               var visibleCenter = context.map().extent().center();
79258               var q = search.property('value').toLowerCase();
79259               if (!q) return result;
79260               var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
79261
79262               if (locationMatch) {
79263                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
79264                 result.push({
79265                   id: -1,
79266                   geometry: 'point',
79267                   type: _t('inspector.location'),
79268                   name: dmsCoordinatePair([loc[1], loc[0]]),
79269                   location: loc
79270                 });
79271               } // A location search takes priority over an ID search
79272
79273
79274               var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W?0*([1-9]\d*)(?:\W|$)/i);
79275
79276               if (idMatch) {
79277                 var elemType = idMatch[1].charAt(0);
79278                 var elemId = idMatch[2];
79279                 result.push({
79280                   id: elemType + elemId,
79281                   geometry: elemType === 'n' ? 'point' : elemType === 'w' ? 'line' : 'relation',
79282                   type: elemType === 'n' ? _t('inspector.node') : elemType === 'w' ? _t('inspector.way') : _t('inspector.relation'),
79283                   name: elemId
79284                 });
79285               }
79286
79287               var allEntities = graph.entities;
79288               var localResults = [];
79289
79290               for (var id in allEntities) {
79291                 var entity = allEntities[id];
79292                 if (!entity) continue;
79293                 var name = utilDisplayName(entity) || '';
79294                 if (name.toLowerCase().indexOf(q) < 0) continue;
79295                 var matched = _mainPresetIndex.match(entity, graph);
79296                 var type = matched && matched.name() || utilDisplayType(entity.id);
79297                 var extent = entity.extent(graph);
79298                 var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
79299                 localResults.push({
79300                   id: entity.id,
79301                   entity: entity,
79302                   geometry: entity.geometry(graph),
79303                   type: type,
79304                   name: name,
79305                   distance: distance
79306                 });
79307                 if (localResults.length > 100) break;
79308               }
79309
79310               localResults = localResults.sort(function byDistance(a, b) {
79311                 return a.distance - b.distance;
79312               });
79313               result = result.concat(localResults);
79314
79315               (_geocodeResults || []).forEach(function (d) {
79316                 if (d.osm_type && d.osm_id) {
79317                   // some results may be missing these - #1890
79318                   // Make a temporary osmEntity so we can preset match
79319                   // and better localize the search result - #4725
79320                   var id = osmEntity.id.fromOSM(d.osm_type, d.osm_id);
79321                   var tags = {};
79322                   tags[d["class"]] = d.type;
79323                   var attrs = {
79324                     id: id,
79325                     type: d.osm_type,
79326                     tags: tags
79327                   };
79328
79329                   if (d.osm_type === 'way') {
79330                     // for ways, add some fake closed nodes
79331                     attrs.nodes = ['a', 'a']; // so that geometry area is possible
79332                   }
79333
79334                   var tempEntity = osmEntity(attrs);
79335                   var tempGraph = coreGraph([tempEntity]);
79336                   var matched = _mainPresetIndex.match(tempEntity, tempGraph);
79337                   var type = matched && matched.name() || utilDisplayType(id);
79338                   result.push({
79339                     id: tempEntity.id,
79340                     geometry: tempEntity.geometry(tempGraph),
79341                     type: type,
79342                     name: d.display_name,
79343                     extent: new geoExtent([parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])], [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
79344                   });
79345                 }
79346               });
79347
79348               if (q.match(/^[0-9]+$/)) {
79349                 // if query is just a number, possibly an OSM ID without a prefix
79350                 result.push({
79351                   id: 'n' + q,
79352                   geometry: 'point',
79353                   type: _t('inspector.node'),
79354                   name: q
79355                 });
79356                 result.push({
79357                   id: 'w' + q,
79358                   geometry: 'line',
79359                   type: _t('inspector.way'),
79360                   name: q
79361                 });
79362                 result.push({
79363                   id: 'r' + q,
79364                   geometry: 'relation',
79365                   type: _t('inspector.relation'),
79366                   name: q
79367                 });
79368               }
79369
79370               return result;
79371             }
79372
79373             function drawList() {
79374               var value = search.property('value');
79375               var results = features();
79376               list.classed('filtered', value.length);
79377               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'));
79378               resultsIndicator.append('span').attr('class', 'entity-name');
79379               list.selectAll('.no-results-item .entity-name').html(_t.html('geocoder.no_results_worldwide'));
79380
79381               if (services.geocoder) {
79382                 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').html(_t.html('geocoder.search'));
79383               }
79384
79385               list.selectAll('.no-results-item').style('display', value.length && !results.length ? 'block' : 'none');
79386               list.selectAll('.geocode-item').style('display', value && _geocodeResults === undefined ? 'block' : 'none');
79387               list.selectAll('.feature-list-item').data([-1]).remove();
79388               var items = list.selectAll('.feature-list-item').data(results, function (d) {
79389                 return d.id;
79390               });
79391               var enter = items.enter().insert('button', '.geocode-item').attr('class', 'feature-list-item').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
79392               var label = enter.append('div').attr('class', 'label');
79393               label.each(function (d) {
79394                 select(this).call(svgIcon('#iD-icon-' + d.geometry, 'pre-text'));
79395               });
79396               label.append('span').attr('class', 'entity-type').html(function (d) {
79397                 return d.type;
79398               });
79399               label.append('span').attr('class', 'entity-name').html(function (d) {
79400                 return d.name;
79401               });
79402               enter.style('opacity', 0).transition().style('opacity', 1);
79403               items.order();
79404               items.exit().remove();
79405             }
79406
79407             function mouseover(d3_event, d) {
79408               if (d.id === -1) return;
79409               utilHighlightEntities([d.id], true, context);
79410             }
79411
79412             function mouseout(d3_event, d) {
79413               if (d.id === -1) return;
79414               utilHighlightEntities([d.id], false, context);
79415             }
79416
79417             function click(d3_event, d) {
79418               d3_event.preventDefault();
79419
79420               if (d.location) {
79421                 context.map().centerZoomEase([d.location[1], d.location[0]], 19);
79422               } else if (d.entity) {
79423                 utilHighlightEntities([d.id], false, context);
79424                 context.enter(modeSelect(context, [d.entity.id]));
79425                 context.map().zoomToEase(d.entity);
79426               } else {
79427                 // download, zoom to, and select the entity with the given ID
79428                 context.zoomToEntity(d.id);
79429               }
79430             }
79431
79432             function geocoderSearch() {
79433               services.geocoder.search(search.property('value'), function (err, resp) {
79434                 _geocodeResults = resp || [];
79435                 drawList();
79436               });
79437             }
79438           }
79439
79440           return featureList;
79441         }
79442
79443         var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
79444
79445
79446
79447
79448
79449
79450         // eslint-disable-next-line es/no-string-prototype-startswith -- safe
79451         var $startsWith = ''.startsWith;
79452         var min$1 = Math.min;
79453
79454         var CORRECT_IS_REGEXP_LOGIC$1 = correctIsRegexpLogic('startsWith');
79455         // https://github.com/zloirock/core-js/pull/702
79456         var MDN_POLYFILL_BUG$1 = !CORRECT_IS_REGEXP_LOGIC$1 && !!function () {
79457           var descriptor = getOwnPropertyDescriptor$1(String.prototype, 'startsWith');
79458           return descriptor && !descriptor.writable;
79459         }();
79460
79461         // `String.prototype.startsWith` method
79462         // https://tc39.es/ecma262/#sec-string.prototype.startswith
79463         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG$1 && !CORRECT_IS_REGEXP_LOGIC$1 }, {
79464           startsWith: function startsWith(searchString /* , position = 0 */) {
79465             var that = String(requireObjectCoercible(this));
79466             notARegexp(searchString);
79467             var index = toLength(min$1(arguments.length > 1 ? arguments[1] : undefined, that.length));
79468             var search = String(searchString);
79469             return $startsWith
79470               ? $startsWith.call(that, search, index)
79471               : that.slice(index, index + search.length) === search;
79472           }
79473         });
79474
79475         function uiSectionEntityIssues(context) {
79476           // Does the user prefer to expand the active issue?  Useful for viewing tag diff.
79477           // Expand by default so first timers see it - #6408, #8143
79478           var preference = corePreferences('entity-issues.reference.expanded');
79479
79480           var _expanded = preference === null ? true : preference === 'true';
79481
79482           var _entityIDs = [];
79483           var _issues = [];
79484
79485           var _activeIssueID;
79486
79487           var section = uiSection('entity-issues', context).shouldDisplay(function () {
79488             return _issues.length > 0;
79489           }).label(function () {
79490             return _t('inspector.title_count', {
79491               title: _t.html('issues.list_title'),
79492               count: _issues.length
79493             });
79494           }).disclosureContent(renderDisclosureContent);
79495           context.validator().on('validated.entity_issues', function () {
79496             // Refresh on validated events
79497             reloadIssues();
79498             section.reRender();
79499           }).on('focusedIssue.entity_issues', function (issue) {
79500             makeActiveIssue(issue.id);
79501           });
79502
79503           function reloadIssues() {
79504             _issues = context.validator().getSharedEntityIssues(_entityIDs, {
79505               includeDisabledRules: true
79506             });
79507           }
79508
79509           function makeActiveIssue(issueID) {
79510             _activeIssueID = issueID;
79511             section.selection().selectAll('.issue-container').classed('active', function (d) {
79512               return d.id === _activeIssueID;
79513             });
79514           }
79515
79516           function renderDisclosureContent(selection) {
79517             selection.classed('grouped-items-area', true);
79518             _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
79519             var containers = selection.selectAll('.issue-container').data(_issues, function (d) {
79520               return d.id;
79521             }); // Exit
79522
79523             containers.exit().remove(); // Enter
79524
79525             var containersEnter = containers.enter().append('div').attr('class', 'issue-container');
79526             var itemsEnter = containersEnter.append('div').attr('class', function (d) {
79527               return 'issue severity-' + d.severity;
79528             }).on('mouseover.highlight', function (d3_event, d) {
79529               // don't hover-highlight the selected entity
79530               var ids = d.entityIds.filter(function (e) {
79531                 return _entityIDs.indexOf(e) === -1;
79532               });
79533               utilHighlightEntities(ids, true, context);
79534             }).on('mouseout.highlight', function (d3_event, d) {
79535               var ids = d.entityIds.filter(function (e) {
79536                 return _entityIDs.indexOf(e) === -1;
79537               });
79538               utilHighlightEntities(ids, false, context);
79539             });
79540             var labelsEnter = itemsEnter.append('div').attr('class', 'issue-label');
79541             var textEnter = labelsEnter.append('button').attr('class', 'issue-text').on('click', function (d3_event, d) {
79542               makeActiveIssue(d.id); // expand only the clicked item
79543
79544               var extent = d.extent(context.graph());
79545
79546               if (extent) {
79547                 var setZoom = Math.max(context.map().zoom(), 19);
79548                 context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
79549               }
79550             });
79551             textEnter.each(function (d) {
79552               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
79553               select(this).call(svgIcon(iconName, 'issue-icon'));
79554             });
79555             textEnter.append('span').attr('class', 'issue-message');
79556             var infoButton = labelsEnter.append('button').attr('class', 'issue-info-button').attr('title', _t('icons.information')).call(svgIcon('#iD-icon-inspect'));
79557             infoButton.on('click', function (d3_event) {
79558               d3_event.stopPropagation();
79559               d3_event.preventDefault();
79560               this.blur(); // avoid keeping focus on the button - #4641
79561
79562               var container = select(this.parentNode.parentNode.parentNode);
79563               var info = container.selectAll('.issue-info');
79564               var isExpanded = info.classed('expanded');
79565               _expanded = !isExpanded;
79566               corePreferences('entity-issues.reference.expanded', _expanded); // update preference
79567
79568               if (isExpanded) {
79569                 info.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
79570                   info.classed('expanded', false);
79571                 });
79572               } else {
79573                 info.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1').on('end', function () {
79574                   info.style('max-height', null);
79575                 });
79576               }
79577             });
79578             itemsEnter.append('ul').attr('class', 'issue-fix-list');
79579             containersEnter.append('div').attr('class', 'issue-info' + (_expanded ? ' expanded' : '')).style('max-height', _expanded ? null : '0').style('opacity', _expanded ? '1' : '0').each(function (d) {
79580               if (typeof d.reference === 'function') {
79581                 select(this).call(d.reference);
79582               } else {
79583                 select(this).html(_t.html('inspector.no_documentation_key'));
79584               }
79585             }); // Update
79586
79587             containers = containers.merge(containersEnter).classed('active', function (d) {
79588               return d.id === _activeIssueID;
79589             });
79590             containers.selectAll('.issue-message').html(function (d) {
79591               return d.message(context);
79592             }); // fixes
79593
79594             var fixLists = containers.selectAll('.issue-fix-list');
79595             var fixes = fixLists.selectAll('.issue-fix-item').data(function (d) {
79596               return d.fixes ? d.fixes(context) : [];
79597             }, function (fix) {
79598               return fix.id;
79599             });
79600             fixes.exit().remove();
79601             var fixesEnter = fixes.enter().append('li').attr('class', 'issue-fix-item');
79602             var buttons = fixesEnter.append('button').on('click', function (d3_event, d) {
79603               // not all fixes are actionable
79604               if (select(this).attr('disabled') || !d.onClick) return; // Don't run another fix for this issue within a second of running one
79605               // (Necessary for "Select a feature type" fix. Most fixes should only ever run once)
79606
79607               if (d.issue.dateLastRanFix && new Date() - d.issue.dateLastRanFix < 1000) return;
79608               d.issue.dateLastRanFix = new Date(); // remove hover-highlighting
79609
79610               utilHighlightEntities(d.issue.entityIds.concat(d.entityIds), false, context);
79611               new Promise(function (resolve, reject) {
79612                 d.onClick(context, resolve, reject);
79613
79614                 if (d.onClick.length <= 1) {
79615                   // if the fix doesn't take any completion parameters then consider it resolved
79616                   resolve();
79617                 }
79618               }).then(function () {
79619                 // revalidate whenever the fix has finished running successfully
79620                 context.validator().validate();
79621               });
79622             }).on('mouseover.highlight', function (d3_event, d) {
79623               utilHighlightEntities(d.entityIds, true, context);
79624             }).on('mouseout.highlight', function (d3_event, d) {
79625               utilHighlightEntities(d.entityIds, false, context);
79626             });
79627             buttons.each(function (d) {
79628               var iconName = d.icon || 'iD-icon-wrench';
79629
79630               if (iconName.startsWith('maki')) {
79631                 iconName += '-15';
79632               }
79633
79634               select(this).call(svgIcon('#' + iconName, 'fix-icon'));
79635             });
79636             buttons.append('span').attr('class', 'fix-message').html(function (d) {
79637               return d.title;
79638             });
79639             fixesEnter.merge(fixes).selectAll('button').classed('actionable', function (d) {
79640               return d.onClick;
79641             }).attr('disabled', function (d) {
79642               return d.onClick ? null : 'true';
79643             }).attr('title', function (d) {
79644               if (d.disabledReason) {
79645                 return d.disabledReason;
79646               }
79647
79648               return null;
79649             });
79650           }
79651
79652           section.entityIDs = function (val) {
79653             if (!arguments.length) return _entityIDs;
79654
79655             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
79656               _entityIDs = val;
79657               _activeIssueID = null;
79658               reloadIssues();
79659             }
79660
79661             return section;
79662           };
79663
79664           return section;
79665         }
79666
79667         function uiPresetIcon() {
79668           var _preset;
79669
79670           var _geometry;
79671
79672           var _sizeClass = 'medium';
79673
79674           function isSmall() {
79675             return _sizeClass === 'small';
79676           }
79677
79678           function presetIcon(selection) {
79679             selection.each(render);
79680           }
79681
79682           function getIcon(p, geom) {
79683             if (isSmall() && p.isFallback && p.isFallback()) return 'iD-icon-' + p.id;
79684             if (p.icon) return p.icon;
79685             if (geom === 'line') return 'iD-other-line';
79686             if (geom === 'vertex') return p.isFallback() ? '' : 'temaki-vertex';
79687             if (isSmall() && geom === 'point') return '';
79688             return 'maki-marker-stroked';
79689           }
79690
79691           function renderPointBorder(container, drawPoint) {
79692             var pointBorder = container.selectAll('.preset-icon-point-border').data(drawPoint ? [0] : []);
79693             pointBorder.exit().remove();
79694             var pointBorderEnter = pointBorder.enter();
79695             var w = 40;
79696             var h = 40;
79697             pointBorderEnter.append('svg').attr('class', 'preset-icon-fill preset-icon-point-border').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(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');
79698             pointBorder = pointBorderEnter.merge(pointBorder);
79699           }
79700
79701           function renderCategoryBorder(container, category) {
79702             var categoryBorder = container.selectAll('.preset-icon-category-border').data(category ? [0] : []);
79703             categoryBorder.exit().remove();
79704             var categoryBorderEnter = categoryBorder.enter();
79705             var d = 60;
79706             var svgEnter = categoryBorderEnter.append('svg').attr('class', 'preset-icon-fill preset-icon-category-border').attr('width', d).attr('height', d).attr('viewBox', "0 0 ".concat(d, " ").concat(d));
79707             ['fill', 'stroke'].forEach(function (klass) {
79708               svgEnter.append('path').attr('class', "area ".concat(klass)).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');
79709             });
79710             categoryBorder = categoryBorderEnter.merge(categoryBorder);
79711
79712             if (category) {
79713               var tagClasses = svgTagClasses().getClassesString(category.members.collection[0].addTags, '');
79714               categoryBorder.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
79715               categoryBorder.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
79716             }
79717           }
79718
79719           function renderCircleFill(container, drawVertex) {
79720             var vertexFill = container.selectAll('.preset-icon-fill-vertex').data(drawVertex ? [0] : []);
79721             vertexFill.exit().remove();
79722             var vertexFillEnter = vertexFill.enter();
79723             var w = 60;
79724             var h = 60;
79725             var d = 40;
79726             vertexFillEnter.append('svg').attr('class', 'preset-icon-fill preset-icon-fill-vertex').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h)).append('circle').attr('cx', w / 2).attr('cy', h / 2).attr('r', d / 2);
79727             vertexFill = vertexFillEnter.merge(vertexFill);
79728           }
79729
79730           function renderSquareFill(container, drawArea, tagClasses) {
79731             var fill = container.selectAll('.preset-icon-fill-area').data(drawArea ? [0] : []);
79732             fill.exit().remove();
79733             var fillEnter = fill.enter();
79734             var d = isSmall() ? 40 : 60;
79735             var w = d;
79736             var h = d;
79737             var l = d * 2 / 3;
79738             var c1 = (w - l) / 2;
79739             var c2 = c1 + l;
79740             fillEnter = fillEnter.append('svg').attr('class', 'preset-icon-fill preset-icon-fill-area').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
79741             ['fill', 'stroke'].forEach(function (klass) {
79742               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));
79743             });
79744             var rVertex = 2.5;
79745             [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach(function (point) {
79746               fillEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', rVertex);
79747             });
79748
79749             if (!isSmall()) {
79750               var rMidpoint = 1.25;
79751               [[c1, w / 2], [c2, w / 2], [h / 2, c1], [h / 2, c2]].forEach(function (point) {
79752                 fillEnter.append('circle').attr('class', 'midpoint').attr('cx', point[0]).attr('cy', point[1]).attr('r', rMidpoint);
79753               });
79754             }
79755
79756             fill = fillEnter.merge(fill);
79757             fill.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
79758             fill.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
79759           }
79760
79761           function renderLine(container, drawLine, tagClasses) {
79762             var line = container.selectAll('.preset-icon-line').data(drawLine ? [0] : []);
79763             line.exit().remove();
79764             var lineEnter = line.enter();
79765             var d = isSmall() ? 40 : 60; // draw the line parametrically
79766
79767             var w = d;
79768             var h = d;
79769             var y = Math.round(d * 0.72);
79770             var l = Math.round(d * 0.6);
79771             var r = 2.5;
79772             var x1 = (w - l) / 2;
79773             var x2 = x1 + l;
79774             lineEnter = lineEnter.append('svg').attr('class', 'preset-icon-line').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
79775             ['casing', 'stroke'].forEach(function (klass) {
79776               lineEnter.append('path').attr('d', "M".concat(x1, " ").concat(y, " L").concat(x2, " ").concat(y)).attr('class', "line ".concat(klass));
79777             });
79778             [[x1 - 1, y], [x2 + 1, y]].forEach(function (point) {
79779               lineEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
79780             });
79781             line = lineEnter.merge(line);
79782             line.selectAll('path.stroke').attr('class', "line stroke ".concat(tagClasses));
79783             line.selectAll('path.casing').attr('class', "line casing ".concat(tagClasses));
79784           }
79785
79786           function renderRoute(container, drawRoute, p) {
79787             var route = container.selectAll('.preset-icon-route').data(drawRoute ? [0] : []);
79788             route.exit().remove();
79789             var routeEnter = route.enter();
79790             var d = isSmall() ? 40 : 60; // draw the route parametrically
79791
79792             var w = d;
79793             var h = d;
79794             var y1 = Math.round(d * 0.80);
79795             var y2 = Math.round(d * 0.68);
79796             var l = Math.round(d * 0.6);
79797             var r = 2;
79798             var x1 = (w - l) / 2;
79799             var x2 = x1 + l / 3;
79800             var x3 = x2 + l / 3;
79801             var x4 = x3 + l / 3;
79802             routeEnter = routeEnter.append('svg').attr('class', 'preset-icon-route').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
79803             ['casing', 'stroke'].forEach(function (klass) {
79804               routeEnter.append('path').attr('d', "M".concat(x1, " ").concat(y1, " L").concat(x2, " ").concat(y2)).attr('class', "segment0 line ".concat(klass));
79805               routeEnter.append('path').attr('d', "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y1)).attr('class', "segment1 line ".concat(klass));
79806               routeEnter.append('path').attr('d', "M".concat(x3, " ").concat(y1, " L").concat(x4, " ").concat(y2)).attr('class', "segment2 line ".concat(klass));
79807             });
79808             [[x1, y1], [x2, y2], [x3, y1], [x4, y2]].forEach(function (point) {
79809               routeEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
79810             });
79811             route = routeEnter.merge(route);
79812
79813             if (drawRoute) {
79814               var routeType = p.tags.type === 'waterway' ? 'waterway' : p.tags.route;
79815               var segmentPresetIDs = routeSegments[routeType];
79816
79817               for (var i in segmentPresetIDs) {
79818                 var segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i]);
79819                 var segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, '');
79820                 route.selectAll("path.stroke.segment".concat(i)).attr('class', "segment".concat(i, " line stroke ").concat(segmentTagClasses));
79821                 route.selectAll("path.casing.segment".concat(i)).attr('class', "segment".concat(i, " line casing ").concat(segmentTagClasses));
79822               }
79823             }
79824           }
79825
79826           function renderSvgIcon(container, picon, geom, isFramed, category, tagClasses) {
79827             var isMaki = picon && /^maki-/.test(picon);
79828             var isTemaki = picon && /^temaki-/.test(picon);
79829             var isFa = picon && /^fa[srb]-/.test(picon);
79830             var isiDIcon = picon && !(isMaki || isTemaki || isFa);
79831             var icon = container.selectAll('.preset-icon').data(picon ? [0] : []);
79832             icon.exit().remove();
79833             icon = icon.enter().append('div').attr('class', 'preset-icon').call(svgIcon('')).merge(icon);
79834             icon.attr('class', 'preset-icon ' + (geom ? geom + '-geom' : '')).classed('category', category).classed('framed', isFramed).classed('preset-icon-iD', isiDIcon);
79835             icon.selectAll('svg').attr('class', 'icon ' + picon + ' ' + (!isiDIcon && geom !== 'line' ? '' : tagClasses));
79836             var suffix = '';
79837
79838             if (isMaki) {
79839               suffix = isSmall() && geom === 'point' ? '-11' : '-15';
79840             }
79841
79842             icon.selectAll('use').attr('href', '#' + picon + suffix);
79843           }
79844
79845           function renderImageIcon(container, imageURL) {
79846             var imageIcon = container.selectAll('img.image-icon').data(imageURL ? [0] : []);
79847             imageIcon.exit().remove();
79848             imageIcon = imageIcon.enter().append('img').attr('class', 'image-icon').on('load', function () {
79849               return container.classed('showing-img', true);
79850             }).on('error', function () {
79851               return container.classed('showing-img', false);
79852             }).merge(imageIcon);
79853             imageIcon.attr('src', imageURL);
79854           } // Route icons are drawn with a zigzag annotation underneath:
79855           //     o   o
79856           //    / \ /
79857           //   o   o
79858           // This dataset defines the styles that are used to draw the zigzag segments.
79859
79860
79861           var routeSegments = {
79862             bicycle: ['highway/cycleway', 'highway/cycleway', 'highway/cycleway'],
79863             bus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
79864             trolleybus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
79865             detour: ['highway/tertiary', 'highway/residential', 'highway/unclassified'],
79866             ferry: ['route/ferry', 'route/ferry', 'route/ferry'],
79867             foot: ['highway/footway', 'highway/footway', 'highway/footway'],
79868             hiking: ['highway/path', 'highway/path', 'highway/path'],
79869             horse: ['highway/bridleway', 'highway/bridleway', 'highway/bridleway'],
79870             light_rail: ['railway/light_rail', 'railway/light_rail', 'railway/light_rail'],
79871             monorail: ['railway/monorail', 'railway/monorail', 'railway/monorail'],
79872             mtb: ['highway/path', 'highway/track', 'highway/bridleway'],
79873             pipeline: ['man_made/pipeline', 'man_made/pipeline', 'man_made/pipeline'],
79874             piste: ['piste/downhill', 'piste/hike', 'piste/nordic'],
79875             power: ['power/line', 'power/line', 'power/line'],
79876             road: ['highway/secondary', 'highway/primary', 'highway/trunk'],
79877             subway: ['railway/subway', 'railway/subway', 'railway/subway'],
79878             train: ['railway/rail', 'railway/rail', 'railway/rail'],
79879             tram: ['railway/tram', 'railway/tram', 'railway/tram'],
79880             waterway: ['waterway/stream', 'waterway/stream', 'waterway/stream']
79881           };
79882
79883           function render() {
79884             var p = _preset.apply(this, arguments);
79885
79886             var geom = _geometry ? _geometry.apply(this, arguments) : null;
79887
79888             if (geom === 'relation' && p.tags && (p.tags.type === 'route' && p.tags.route && routeSegments[p.tags.route] || p.tags.type === 'waterway')) {
79889               geom = 'route';
79890             }
79891
79892             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
79893             var isFallback = isSmall() && p.isFallback && p.isFallback();
79894             var imageURL = showThirdPartyIcons === 'true' && p.imageURL;
79895             var picon = getIcon(p, geom);
79896             var isCategory = !p.setTags;
79897             var drawPoint = picon && geom === 'point' && isSmall() && !isFallback;
79898             var drawVertex = picon !== null && geom === 'vertex' && (!isSmall() || !isFallback);
79899             var drawLine = picon && geom === 'line' && !isFallback && !isCategory;
79900             var drawArea = picon && geom === 'area' && !isFallback && !isCategory;
79901             var drawRoute = picon && geom === 'route';
79902             var isFramed = drawVertex || drawArea || drawLine || drawRoute || isCategory;
79903             var tags = !isCategory ? p.setTags({}, geom) : {};
79904
79905             for (var k in tags) {
79906               if (tags[k] === '*') {
79907                 tags[k] = 'yes';
79908               }
79909             }
79910
79911             var tagClasses = svgTagClasses().getClassesString(tags, '');
79912             var selection = select(this);
79913             var container = selection.selectAll('.preset-icon-container').data([0]);
79914             container = container.enter().append('div').attr('class', "preset-icon-container ".concat(_sizeClass)).merge(container);
79915             container.classed('showing-img', !!imageURL).classed('fallback', isFallback);
79916             renderCategoryBorder(container, isCategory && p);
79917             renderPointBorder(container, drawPoint);
79918             renderCircleFill(container, drawVertex);
79919             renderSquareFill(container, drawArea, tagClasses);
79920             renderLine(container, drawLine, tagClasses);
79921             renderRoute(container, drawRoute, p);
79922             renderSvgIcon(container, picon, geom, isFramed, isCategory, tagClasses);
79923             renderImageIcon(container, imageURL);
79924           }
79925
79926           presetIcon.preset = function (val) {
79927             if (!arguments.length) return _preset;
79928             _preset = utilFunctor(val);
79929             return presetIcon;
79930           };
79931
79932           presetIcon.geometry = function (val) {
79933             if (!arguments.length) return _geometry;
79934             _geometry = utilFunctor(val);
79935             return presetIcon;
79936           };
79937
79938           presetIcon.sizeClass = function (val) {
79939             if (!arguments.length) return _sizeClass;
79940             _sizeClass = val;
79941             return presetIcon;
79942           };
79943
79944           return presetIcon;
79945         }
79946
79947         function uiSectionFeatureType(context) {
79948           var dispatch = dispatch$8('choose');
79949           var _entityIDs = [];
79950           var _presets = [];
79951
79952           var _tagReference;
79953
79954           var section = uiSection('feature-type', context).label(_t.html('inspector.feature_type')).disclosureContent(renderDisclosureContent);
79955
79956           function renderDisclosureContent(selection) {
79957             selection.classed('preset-list-item', true);
79958             selection.classed('mixed-types', _presets.length > 1);
79959             var presetButtonWrap = selection.selectAll('.preset-list-button-wrap').data([0]).enter().append('div').attr('class', 'preset-list-button-wrap');
79960             var presetButton = presetButtonWrap.append('button').attr('class', 'preset-list-button preset-reset').call(uiTooltip().title(_t.html('inspector.back_tooltip')).placement('bottom'));
79961             presetButton.append('div').attr('class', 'preset-icon-container');
79962             presetButton.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
79963             presetButtonWrap.append('div').attr('class', 'accessory-buttons');
79964             var tagReferenceBodyWrap = selection.selectAll('.tag-reference-body-wrap').data([0]);
79965             tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append('div').attr('class', 'tag-reference-body-wrap').merge(tagReferenceBodyWrap); // update header
79966
79967             if (_tagReference) {
79968               selection.selectAll('.preset-list-button-wrap .accessory-buttons').style('display', _presets.length === 1 ? null : 'none').call(_tagReference.button);
79969               tagReferenceBodyWrap.style('display', _presets.length === 1 ? null : 'none').call(_tagReference.body);
79970             }
79971
79972             selection.selectAll('.preset-reset').on('click', function () {
79973               dispatch.call('choose', this, _presets);
79974             }).on('pointerdown pointerup mousedown mouseup', function (d3_event) {
79975               d3_event.preventDefault();
79976               d3_event.stopPropagation();
79977             });
79978             var geometries = entityGeometries();
79979             selection.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')));
79980             var names = _presets.length === 1 ? [_presets[0].nameLabel(), _presets[0].subtitleLabel()].filter(Boolean) : [_t('inspector.multiple_types')];
79981             var label = selection.select('.label-inner');
79982             var nameparts = label.selectAll('.namepart').data(names, function (d) {
79983               return d;
79984             });
79985             nameparts.exit().remove();
79986             nameparts.enter().append('div').attr('class', 'namepart').html(function (d) {
79987               return d;
79988             });
79989           }
79990
79991           section.entityIDs = function (val) {
79992             if (!arguments.length) return _entityIDs;
79993             _entityIDs = val;
79994             return section;
79995           };
79996
79997           section.presets = function (val) {
79998             if (!arguments.length) return _presets; // don't reload the same preset
79999
80000             if (!utilArrayIdentical(val, _presets)) {
80001               _presets = val;
80002
80003               if (_presets.length === 1) {
80004                 _tagReference = uiTagReference(_presets[0].reference()).showing(false);
80005               }
80006             }
80007
80008             return section;
80009           };
80010
80011           function entityGeometries() {
80012             var counts = {};
80013
80014             for (var i in _entityIDs) {
80015               var geometry = context.graph().geometry(_entityIDs[i]);
80016               if (!counts[geometry]) counts[geometry] = 0;
80017               counts[geometry] += 1;
80018             }
80019
80020             return Object.keys(counts).sort(function (geom1, geom2) {
80021               return counts[geom2] - counts[geom1];
80022             });
80023           }
80024
80025           return utilRebind(section, dispatch, 'on');
80026         }
80027
80028         // It borrows some code from uiHelp
80029
80030         function uiFieldHelp(context, fieldName) {
80031           var fieldHelp = {};
80032
80033           var _inspector = select(null);
80034
80035           var _wrap = select(null);
80036
80037           var _body = select(null);
80038
80039           var fieldHelpKeys = {
80040             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']]]
80041           };
80042           var fieldHelpHeadings = {};
80043           var replacements = {
80044             distField: _t.html('restriction.controls.distance'),
80045             viaField: _t.html('restriction.controls.via'),
80046             fromShadow: icon('#iD-turn-shadow', 'inline shadow from'),
80047             allowShadow: icon('#iD-turn-shadow', 'inline shadow allow'),
80048             restrictShadow: icon('#iD-turn-shadow', 'inline shadow restrict'),
80049             onlyShadow: icon('#iD-turn-shadow', 'inline shadow only'),
80050             allowTurn: icon('#iD-turn-yes', 'inline turn'),
80051             restrictTurn: icon('#iD-turn-no', 'inline turn'),
80052             onlyTurn: icon('#iD-turn-only', 'inline turn')
80053           }; // For each section, squash all the texts into a single markdown document
80054
80055           var docs = fieldHelpKeys[fieldName].map(function (key) {
80056             var helpkey = 'help.field.' + fieldName + '.' + key[0];
80057             var text = key[1].reduce(function (all, part) {
80058               var subkey = helpkey + '.' + part;
80059               var depth = fieldHelpHeadings[subkey]; // is this subkey a heading?
80060
80061               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
80062
80063               return all + hhh + _t.html(subkey, replacements) + '\n\n';
80064             }, '');
80065             return {
80066               key: helpkey,
80067               title: _t.html(helpkey + '.title'),
80068               html: marked_1(text.trim())
80069             };
80070           });
80071
80072           function show() {
80073             updatePosition();
80074
80075             _body.classed('hide', false).style('opacity', '0').transition().duration(200).style('opacity', '1');
80076           }
80077
80078           function hide() {
80079             _body.classed('hide', true).transition().duration(200).style('opacity', '0').on('end', function () {
80080               _body.classed('hide', true);
80081             });
80082           }
80083
80084           function clickHelp(index) {
80085             var d = docs[index];
80086             var tkeys = fieldHelpKeys[fieldName][index][1];
80087
80088             _body.selectAll('.field-help-nav-item').classed('active', function (d, i) {
80089               return i === index;
80090             });
80091
80092             var content = _body.selectAll('.field-help-content').html(d.html); // class the paragraphs so we can find and style them
80093
80094
80095             content.selectAll('p').attr('class', function (d, i) {
80096               return tkeys[i];
80097             }); // insert special content for certain help sections
80098
80099             if (d.key === 'help.field.restrictions.inspecting') {
80100               content.insert('img', 'p.from_shadow').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_inspect.gif'));
80101             } else if (d.key === 'help.field.restrictions.modifying') {
80102               content.insert('img', 'p.allow_turn').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_modify.gif'));
80103             }
80104           }
80105
80106           fieldHelp.button = function (selection) {
80107             if (_body.empty()) return;
80108             var button = selection.selectAll('.field-help-button').data([0]); // enter/update
80109
80110             button.enter().append('button').attr('class', 'field-help-button').call(svgIcon('#iD-icon-help')).merge(button).on('click', function (d3_event) {
80111               d3_event.stopPropagation();
80112               d3_event.preventDefault();
80113
80114               if (_body.classed('hide')) {
80115                 show();
80116               } else {
80117                 hide();
80118               }
80119             });
80120           };
80121
80122           function updatePosition() {
80123             var wrap = _wrap.node();
80124
80125             var inspector = _inspector.node();
80126
80127             var wRect = wrap.getBoundingClientRect();
80128             var iRect = inspector.getBoundingClientRect();
80129
80130             _body.style('top', wRect.top + inspector.scrollTop - iRect.top + 'px');
80131           }
80132
80133           fieldHelp.body = function (selection) {
80134             // This control expects the field to have a form-field-input-wrap div
80135             _wrap = selection.selectAll('.form-field-input-wrap');
80136             if (_wrap.empty()) return; // absolute position relative to the inspector, so it "floats" above the fields
80137
80138             _inspector = context.container().select('.sidebar .entity-editor-pane .inspector-body');
80139             if (_inspector.empty()) return;
80140             _body = _inspector.selectAll('.field-help-body').data([0]);
80141
80142             var enter = _body.enter().append('div').attr('class', 'field-help-body hide'); // initially hidden
80143
80144
80145             var titleEnter = enter.append('div').attr('class', 'field-help-title cf');
80146             titleEnter.append('h2').attr('class', _mainLocalizer.textDirection() === 'rtl' ? 'fr' : 'fl').html(_t.html('help.field.' + fieldName + '.title'));
80147             titleEnter.append('button').attr('class', 'fr close').on('click', function (d3_event) {
80148               d3_event.stopPropagation();
80149               d3_event.preventDefault();
80150               hide();
80151             }).call(svgIcon('#iD-icon-close'));
80152             var navEnter = enter.append('div').attr('class', 'field-help-nav cf');
80153             var titles = docs.map(function (d) {
80154               return d.title;
80155             });
80156             navEnter.selectAll('.field-help-nav-item').data(titles).enter().append('div').attr('class', 'field-help-nav-item').html(function (d) {
80157               return d;
80158             }).on('click', function (d3_event, d) {
80159               d3_event.stopPropagation();
80160               d3_event.preventDefault();
80161               clickHelp(titles.indexOf(d));
80162             });
80163             enter.append('div').attr('class', 'field-help-content');
80164             _body = _body.merge(enter);
80165             clickHelp(0);
80166           };
80167
80168           return fieldHelp;
80169         }
80170
80171         function uiFieldCheck(field, context) {
80172           var dispatch = dispatch$8('change');
80173           var options = field.options;
80174           var values = [];
80175           var texts = [];
80176
80177           var _tags;
80178
80179           var input = select(null);
80180           var text = select(null);
80181           var label = select(null);
80182           var reverser = select(null);
80183
80184           var _impliedYes;
80185
80186           var _entityIDs = [];
80187
80188           var _value;
80189
80190           if (options) {
80191             for (var i in options) {
80192               var v = options[i];
80193               values.push(v === 'undefined' ? undefined : v);
80194               texts.push(field.t.html('options.' + v, {
80195                 'default': v
80196               }));
80197             }
80198           } else {
80199             values = [undefined, 'yes'];
80200             texts = [_t.html('inspector.unknown'), _t.html('inspector.check.yes')];
80201
80202             if (field.type !== 'defaultCheck') {
80203               values.push('no');
80204               texts.push(_t.html('inspector.check.no'));
80205             }
80206           } // Checks tags to see whether an undefined value is "Assumed to be Yes"
80207
80208
80209           function checkImpliedYes() {
80210             _impliedYes = field.id === 'oneway_yes'; // hack: pretend `oneway` field is a `oneway_yes` field
80211             // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
80212
80213             if (field.id === 'oneway') {
80214               var entity = context.entity(_entityIDs[0]);
80215
80216               for (var key in entity.tags) {
80217                 if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
80218                   _impliedYes = true;
80219                   texts[0] = _t.html('_tagging.presets.fields.oneway_yes.options.undefined');
80220                   break;
80221                 }
80222               }
80223             }
80224           }
80225
80226           function reverserHidden() {
80227             if (!context.container().select('div.inspector-hover').empty()) return true;
80228             return !(_value === 'yes' || _impliedYes && !_value);
80229           }
80230
80231           function reverserSetText(selection) {
80232             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
80233             if (reverserHidden() || !entity) return selection;
80234             var first = entity.first();
80235             var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
80236             var pseudoDirection = first < last;
80237             var icon = pseudoDirection ? '#iD-icon-forward' : '#iD-icon-backward';
80238             selection.selectAll('.reverser-span').html(_t.html('inspector.check.reverser')).call(svgIcon(icon, 'inline'));
80239             return selection;
80240           }
80241
80242           var check = function check(selection) {
80243             checkImpliedYes();
80244             label = selection.selectAll('.form-field-input-wrap').data([0]);
80245             var enter = label.enter().append('label').attr('class', 'form-field-input-wrap form-field-input-check');
80246             enter.append('input').property('indeterminate', field.type !== 'defaultCheck').attr('type', 'checkbox').attr('id', field.domId);
80247             enter.append('span').html(texts[0]).attr('class', 'value');
80248
80249             if (field.type === 'onewayCheck') {
80250               enter.append('button').attr('class', 'reverser' + (reverserHidden() ? ' hide' : '')).append('span').attr('class', 'reverser-span');
80251             }
80252
80253             label = label.merge(enter);
80254             input = label.selectAll('input');
80255             text = label.selectAll('span.value');
80256             input.on('click', function (d3_event) {
80257               d3_event.stopPropagation();
80258               var t = {};
80259
80260               if (Array.isArray(_tags[field.key])) {
80261                 if (values.indexOf('yes') !== -1) {
80262                   t[field.key] = 'yes';
80263                 } else {
80264                   t[field.key] = values[0];
80265                 }
80266               } else {
80267                 t[field.key] = values[(values.indexOf(_value) + 1) % values.length];
80268               } // Don't cycle through `alternating` or `reversible` states - #4970
80269               // (They are supported as translated strings, but should not toggle with clicks)
80270
80271
80272               if (t[field.key] === 'reversible' || t[field.key] === 'alternating') {
80273                 t[field.key] = values[0];
80274               }
80275
80276               dispatch.call('change', this, t);
80277             });
80278
80279             if (field.type === 'onewayCheck') {
80280               reverser = label.selectAll('.reverser');
80281               reverser.call(reverserSetText).on('click', function (d3_event) {
80282                 d3_event.preventDefault();
80283                 d3_event.stopPropagation();
80284                 context.perform(function (graph) {
80285                   for (var i in _entityIDs) {
80286                     graph = actionReverse(_entityIDs[i])(graph);
80287                   }
80288
80289                   return graph;
80290                 }, _t('operations.reverse.annotation.line', {
80291                   n: 1
80292                 })); // must manually revalidate since no 'change' event was called
80293
80294                 context.validator().validate();
80295                 select(this).call(reverserSetText);
80296               });
80297             }
80298           };
80299
80300           check.entityIDs = function (val) {
80301             if (!arguments.length) return _entityIDs;
80302             _entityIDs = val;
80303             return check;
80304           };
80305
80306           check.tags = function (tags) {
80307             _tags = tags;
80308
80309             function isChecked(val) {
80310               return val !== 'no' && val !== '' && val !== undefined && val !== null;
80311             }
80312
80313             function textFor(val) {
80314               if (val === '') val = undefined;
80315               var index = values.indexOf(val);
80316               return index !== -1 ? texts[index] : '"' + val + '"';
80317             }
80318
80319             checkImpliedYes();
80320             var isMixed = Array.isArray(tags[field.key]);
80321             _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
80322
80323             if (field.type === 'onewayCheck' && (_value === '1' || _value === '-1')) {
80324               _value = 'yes';
80325             }
80326
80327             input.property('indeterminate', isMixed || field.type !== 'defaultCheck' && !_value).property('checked', isChecked(_value));
80328             text.html(isMixed ? _t.html('inspector.multiple_values') : textFor(_value)).classed('mixed', isMixed);
80329             label.classed('set', !!_value);
80330
80331             if (field.type === 'onewayCheck') {
80332               reverser.classed('hide', reverserHidden()).call(reverserSetText);
80333             }
80334           };
80335
80336           check.focus = function () {
80337             input.node().focus();
80338           };
80339
80340           return utilRebind(check, dispatch, 'on');
80341         }
80342
80343         function uiFieldCombo(field, context) {
80344           var dispatch = dispatch$8('change');
80345
80346           var _isMulti = field.type === 'multiCombo' || field.type === 'manyCombo';
80347
80348           var _isNetwork = field.type === 'networkCombo';
80349
80350           var _isSemi = field.type === 'semiCombo';
80351
80352           var _optarray = field.options;
80353
80354           var _showTagInfoSuggestions = field.type !== 'manyCombo' && field.autoSuggestions !== false;
80355
80356           var _allowCustomValues = field.type !== 'manyCombo' && field.customValues !== false;
80357
80358           var _snake_case = field.snake_case || field.snake_case === undefined;
80359
80360           var _combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(field.caseSensitive).minItems(_isMulti || _isSemi ? 1 : 2);
80361
80362           var _container = select(null);
80363
80364           var _inputWrap = select(null);
80365
80366           var _input = select(null);
80367
80368           var _comboData = [];
80369           var _multiData = [];
80370           var _entityIDs = [];
80371
80372           var _tags;
80373
80374           var _countryCode;
80375
80376           var _staticPlaceholder; // initialize deprecated tags array
80377
80378
80379           var _dataDeprecated = [];
80380           _mainFileFetcher.get('deprecated').then(function (d) {
80381             _dataDeprecated = d;
80382           })["catch"](function () {
80383             /* ignore */
80384           }); // ensure multiCombo field.key ends with a ':'
80385
80386           if (_isMulti && field.key && /[^:]$/.test(field.key)) {
80387             field.key += ':';
80388           }
80389
80390           function snake(s) {
80391             return s.replace(/\s+/g, '_').toLowerCase();
80392           }
80393
80394           function clean(s) {
80395             return s.split(';').map(function (s) {
80396               return s.trim();
80397             }).join(';');
80398           } // returns the tag value for a display value
80399           // (for multiCombo, dval should be the key suffix, not the entire key)
80400
80401
80402           function tagValue(dval) {
80403             dval = clean(dval || '');
80404
80405             var found = _comboData.find(function (o) {
80406               return o.key && clean(o.value) === dval;
80407             });
80408
80409             if (found) return found.key;
80410
80411             if (field.type === 'typeCombo' && !dval) {
80412               return 'yes';
80413             }
80414
80415             return (_snake_case ? snake(dval) : dval) || undefined;
80416           } // returns the display value for a tag value
80417           // (for multiCombo, tval should be the key suffix, not the entire key)
80418
80419
80420           function displayValue(tval) {
80421             tval = tval || '';
80422
80423             if (field.hasTextForStringId('options.' + tval)) {
80424               return field.t('options.' + tval, {
80425                 "default": tval
80426               });
80427             }
80428
80429             if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
80430               return '';
80431             }
80432
80433             return tval;
80434           } // Compute the difference between arrays of objects by `value` property
80435           //
80436           // objectDifference([{value:1}, {value:2}, {value:3}], [{value:2}])
80437           // > [{value:1}, {value:3}]
80438           //
80439
80440
80441           function objectDifference(a, b) {
80442             return a.filter(function (d1) {
80443               return !b.some(function (d2) {
80444                 return !d2.isMixed && d1.value === d2.value;
80445               });
80446             });
80447           }
80448
80449           function initCombo(selection, attachTo) {
80450             if (!_allowCustomValues) {
80451               selection.attr('readonly', 'readonly');
80452             }
80453
80454             if (_showTagInfoSuggestions && services.taginfo) {
80455               selection.call(_combobox.fetcher(setTaginfoValues), attachTo);
80456               setTaginfoValues('', setPlaceholder);
80457             } else {
80458               selection.call(_combobox, attachTo);
80459               setStaticValues(setPlaceholder);
80460             }
80461           }
80462
80463           function setStaticValues(callback) {
80464             if (!_optarray) return;
80465             _comboData = _optarray.map(function (v) {
80466               return {
80467                 key: v,
80468                 value: field.t('options.' + v, {
80469                   "default": v
80470                 }),
80471                 title: v,
80472                 display: field.t.html('options.' + v, {
80473                   "default": v
80474                 }),
80475                 klass: field.hasTextForStringId('options.' + v) ? '' : 'raw-option'
80476               };
80477             });
80478
80479             _combobox.data(objectDifference(_comboData, _multiData));
80480
80481             if (callback) callback(_comboData);
80482           }
80483
80484           function setTaginfoValues(q, callback) {
80485             var fn = _isMulti ? 'multikeys' : 'values';
80486             var query = (_isMulti ? field.key : '') + q;
80487             var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
80488
80489             if (hasCountryPrefix) {
80490               query = _countryCode + ':';
80491             }
80492
80493             var params = {
80494               debounce: q !== '',
80495               key: field.key,
80496               query: query
80497             };
80498
80499             if (_entityIDs.length) {
80500               params.geometry = context.graph().geometry(_entityIDs[0]);
80501             }
80502
80503             services.taginfo[fn](params, function (err, data) {
80504               if (err) return;
80505               data = data.filter(function (d) {
80506                 if (field.type === 'typeCombo' && d.value === 'yes') {
80507                   // don't show the fallback value
80508                   return false;
80509                 } // don't show values with very low usage
80510
80511
80512                 return !d.count || d.count > 10;
80513               });
80514               var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
80515
80516               if (deprecatedValues) {
80517                 // don't suggest deprecated tag values
80518                 data = data.filter(function (d) {
80519                   return deprecatedValues.indexOf(d.value) === -1;
80520                 });
80521               }
80522
80523               if (hasCountryPrefix) {
80524                 data = data.filter(function (d) {
80525                   return d.value.toLowerCase().indexOf(_countryCode + ':') === 0;
80526                 });
80527               } // hide the caret if there are no suggestions
80528
80529
80530               _container.classed('empty-combobox', data.length === 0);
80531
80532               _comboData = data.map(function (d) {
80533                 var k = d.value;
80534                 if (_isMulti) k = k.replace(field.key, '');
80535                 var label = field.t('options.' + k, {
80536                   "default": k
80537                 });
80538                 return {
80539                   key: k,
80540                   value: label,
80541                   display: field.t.html('options.' + k, {
80542                     "default": k
80543                   }),
80544                   title: d.title || label,
80545                   klass: field.hasTextForStringId('options.' + k) ? '' : 'raw-option'
80546                 };
80547               });
80548               _comboData = objectDifference(_comboData, _multiData);
80549               if (callback) callback(_comboData);
80550             });
80551           }
80552
80553           function setPlaceholder(values) {
80554             if (_isMulti || _isSemi) {
80555               _staticPlaceholder = field.placeholder() || _t('inspector.add');
80556             } else {
80557               var vals = values.map(function (d) {
80558                 return d.value;
80559               }).filter(function (s) {
80560                 return s.length < 20;
80561               });
80562               var placeholders = vals.length > 1 ? vals : values.map(function (d) {
80563                 return d.key;
80564               });
80565               _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(', ');
80566             }
80567
80568             if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
80569               _staticPlaceholder += '…';
80570             }
80571
80572             var ph;
80573
80574             if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
80575               ph = _t('inspector.multiple_values');
80576             } else {
80577               ph = _staticPlaceholder;
80578             }
80579
80580             _container.selectAll('input').attr('placeholder', ph);
80581           }
80582
80583           function change() {
80584             var t = {};
80585             var val;
80586
80587             if (_isMulti || _isSemi) {
80588               val = tagValue(utilGetSetValue(_input).replace(/,/g, ';')) || '';
80589
80590               _container.classed('active', false);
80591
80592               utilGetSetValue(_input, '');
80593               var vals = val.split(';').filter(Boolean);
80594               if (!vals.length) return;
80595
80596               if (_isMulti) {
80597                 utilArrayUniq(vals).forEach(function (v) {
80598                   var key = (field.key || '') + v;
80599
80600                   if (_tags) {
80601                     // don't set a multicombo value to 'yes' if it already has a non-'no' value
80602                     // e.g. `language:de=main`
80603                     var old = _tags[key];
80604                     if (typeof old === 'string' && old.toLowerCase() !== 'no') return;
80605                   }
80606
80607                   key = context.cleanTagKey(key);
80608                   field.keys.push(key);
80609                   t[key] = 'yes';
80610                 });
80611               } else if (_isSemi) {
80612                 var arr = _multiData.map(function (d) {
80613                   return d.key;
80614                 });
80615
80616                 arr = arr.concat(vals);
80617                 t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';'));
80618               }
80619
80620               window.setTimeout(function () {
80621                 _input.node().focus();
80622               }, 10);
80623             } else {
80624               var rawValue = utilGetSetValue(_input); // don't override multiple values with blank string
80625
80626               if (!rawValue && Array.isArray(_tags[field.key])) return;
80627               val = context.cleanTagValue(tagValue(rawValue));
80628               t[field.key] = val || undefined;
80629             }
80630
80631             dispatch.call('change', this, t);
80632           }
80633
80634           function removeMultikey(d3_event, d) {
80635             d3_event.preventDefault();
80636             d3_event.stopPropagation();
80637             var t = {};
80638
80639             if (_isMulti) {
80640               t[d.key] = undefined;
80641             } else if (_isSemi) {
80642               var arr = _multiData.map(function (md) {
80643                 return md.key === d.key ? null : md.key;
80644               }).filter(Boolean);
80645
80646               arr = utilArrayUniq(arr);
80647               t[field.key] = arr.length ? arr.join(';') : undefined;
80648             }
80649
80650             dispatch.call('change', this, t);
80651           }
80652
80653           function combo(selection) {
80654             _container = selection.selectAll('.form-field-input-wrap').data([0]);
80655             var type = _isMulti || _isSemi ? 'multicombo' : 'combo';
80656             _container = _container.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + type).merge(_container);
80657
80658             if (_isMulti || _isSemi) {
80659               _container = _container.selectAll('.chiplist').data([0]);
80660               var listClass = 'chiplist'; // Use a separate line for each value in the Destinations and Via fields
80661               // to mimic highway exit signs
80662
80663               if (field.key === 'destination' || field.key === 'via') {
80664                 listClass += ' full-line-chips';
80665               }
80666
80667               _container = _container.enter().append('ul').attr('class', listClass).on('click', function () {
80668                 window.setTimeout(function () {
80669                   _input.node().focus();
80670                 }, 10);
80671               }).merge(_container);
80672               _inputWrap = _container.selectAll('.input-wrap').data([0]);
80673               _inputWrap = _inputWrap.enter().append('li').attr('class', 'input-wrap').merge(_inputWrap);
80674               _input = _inputWrap.selectAll('input').data([0]);
80675             } else {
80676               _input = _container.selectAll('input').data([0]);
80677             }
80678
80679             _input = _input.enter().append('input').attr('type', 'text').attr('id', field.domId).call(utilNoAuto).call(initCombo, selection).merge(_input);
80680
80681             if (_isNetwork) {
80682               var extent = combinedEntityExtent();
80683               var countryCode = extent && iso1A2Code(extent.center());
80684               _countryCode = countryCode && countryCode.toLowerCase();
80685             }
80686
80687             _input.on('change', change).on('blur', change);
80688
80689             _input.on('keydown.field', function (d3_event) {
80690               switch (d3_event.keyCode) {
80691                 case 13:
80692                   // ↩ Return
80693                   _input.node().blur(); // blurring also enters the value
80694
80695
80696                   d3_event.stopPropagation();
80697                   break;
80698               }
80699             });
80700
80701             if (_isMulti || _isSemi) {
80702               _combobox.on('accept', function () {
80703                 _input.node().blur();
80704
80705                 _input.node().focus();
80706               });
80707
80708               _input.on('focus', function () {
80709                 _container.classed('active', true);
80710               });
80711             }
80712           }
80713
80714           combo.tags = function (tags) {
80715             _tags = tags;
80716
80717             if (_isMulti || _isSemi) {
80718               _multiData = [];
80719               var maxLength;
80720
80721               if (_isMulti) {
80722                 // Build _multiData array containing keys already set..
80723                 for (var k in tags) {
80724                   if (field.key && k.indexOf(field.key) !== 0) continue;
80725                   if (!field.key && field.keys.indexOf(k) === -1) continue;
80726                   var v = tags[k];
80727                   if (!v || typeof v === 'string' && v.toLowerCase() === 'no') continue;
80728                   var suffix = field.key ? k.substr(field.key.length) : k;
80729
80730                   _multiData.push({
80731                     key: k,
80732                     value: displayValue(suffix),
80733                     isMixed: Array.isArray(v)
80734                   });
80735                 }
80736
80737                 if (field.key) {
80738                   // Set keys for form-field modified (needed for undo and reset buttons)..
80739                   field.keys = _multiData.map(function (d) {
80740                     return d.key;
80741                   }); // limit the input length so it fits after prepending the key prefix
80742
80743                   maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
80744                 } else {
80745                   maxLength = context.maxCharsForTagKey();
80746                 }
80747               } else if (_isSemi) {
80748                 var allValues = [];
80749                 var commonValues;
80750
80751                 if (Array.isArray(tags[field.key])) {
80752                   tags[field.key].forEach(function (tagVal) {
80753                     var thisVals = utilArrayUniq((tagVal || '').split(';')).filter(Boolean);
80754                     allValues = allValues.concat(thisVals);
80755
80756                     if (!commonValues) {
80757                       commonValues = thisVals;
80758                     } else {
80759                       commonValues = commonValues.filter(function (value) {
80760                         return thisVals.includes(value);
80761                       });
80762                     }
80763                   });
80764                   allValues = utilArrayUniq(allValues).filter(Boolean);
80765                 } else {
80766                   allValues = utilArrayUniq((tags[field.key] || '').split(';')).filter(Boolean);
80767                   commonValues = allValues;
80768                 }
80769
80770                 _multiData = allValues.map(function (v) {
80771                   return {
80772                     key: v,
80773                     value: displayValue(v),
80774                     isMixed: !commonValues.includes(v)
80775                   };
80776                 });
80777                 var currLength = utilUnicodeCharsCount(commonValues.join(';')); // limit the input length to the remaining available characters
80778
80779                 maxLength = context.maxCharsForTagValue() - currLength;
80780
80781                 if (currLength > 0) {
80782                   // account for the separator if a new value will be appended to existing
80783                   maxLength -= 1;
80784                 }
80785               } // a negative maxlength doesn't make sense
80786
80787
80788               maxLength = Math.max(0, maxLength);
80789               var allowDragAndDrop = _isSemi // only semiCombo values are ordered
80790               && !Array.isArray(tags[field.key]); // Exclude existing multikeys from combo options..
80791
80792               var available = objectDifference(_comboData, _multiData);
80793
80794               _combobox.data(available); // Hide 'Add' button if this field uses fixed set of
80795               // options and they're all currently used,
80796               // or if the field is already at its character limit
80797
80798
80799               var hideAdd = !_allowCustomValues && !available.length || maxLength <= 0;
80800
80801               _container.selectAll('.chiplist .input-wrap').style('display', hideAdd ? 'none' : null); // Render chips
80802
80803
80804               var chips = _container.selectAll('.chip').data(_multiData);
80805
80806               chips.exit().remove();
80807               var enter = chips.enter().insert('li', '.input-wrap').attr('class', 'chip');
80808               enter.append('span');
80809               enter.append('a');
80810               chips = chips.merge(enter).order().classed('raw-value', function (d) {
80811                 var k = d.key;
80812                 if (_isMulti) k = k.replace(field.key, '');
80813                 return !field.hasTextForStringId('options.' + k);
80814               }).classed('draggable', allowDragAndDrop).classed('mixed', function (d) {
80815                 return d.isMixed;
80816               }).attr('title', function (d) {
80817                 return d.isMixed ? _t('inspector.unshared_value_tooltip') : null;
80818               });
80819
80820               if (allowDragAndDrop) {
80821                 registerDragAndDrop(chips);
80822               }
80823
80824               chips.select('span').html(function (d) {
80825                 return d.value;
80826               });
80827               chips.select('a').attr('href', '#').on('click', removeMultikey).attr('class', 'remove').html('×');
80828             } else {
80829               var isMixed = Array.isArray(tags[field.key]);
80830               var mixedValues = isMixed && tags[field.key].map(function (val) {
80831                 return displayValue(val);
80832               }).filter(Boolean);
80833               var showsValue = !isMixed && tags[field.key] && !(field.type === 'typeCombo' && tags[field.key] === 'yes');
80834               var isRawValue = showsValue && !field.hasTextForStringId('options.' + tags[field.key]);
80835               var isKnownValue = showsValue && !isRawValue;
80836               var isReadOnly = !_allowCustomValues || isKnownValue;
80837               utilGetSetValue(_input, !isMixed ? displayValue(tags[field.key]) : '').classed('raw-value', isRawValue).classed('known-value', isKnownValue).attr('readonly', isReadOnly ? 'readonly' : undefined).attr('title', isMixed ? mixedValues.join('\n') : undefined).attr('placeholder', isMixed ? _t('inspector.multiple_values') : _staticPlaceholder || '').classed('mixed', isMixed).on('keydown.deleteCapture', function (d3_event) {
80838                 if (isReadOnly && isKnownValue && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
80839                   d3_event.preventDefault();
80840                   d3_event.stopPropagation();
80841                   var t = {};
80842                   t[field.key] = undefined;
80843                   dispatch.call('change', this, t);
80844                 }
80845               });
80846             }
80847           };
80848
80849           function registerDragAndDrop(selection) {
80850             // allow drag and drop re-ordering of chips
80851             var dragOrigin, targetIndex;
80852             selection.call(d3_drag().on('start', function (d3_event) {
80853               dragOrigin = {
80854                 x: d3_event.x,
80855                 y: d3_event.y
80856               };
80857               targetIndex = null;
80858             }).on('drag', function (d3_event) {
80859               var x = d3_event.x - dragOrigin.x,
80860                   y = d3_event.y - dragOrigin.y;
80861               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
80862               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
80863               var index = selection.nodes().indexOf(this);
80864               select(this).classed('dragging', true);
80865               targetIndex = null;
80866               var targetIndexOffsetTop = null;
80867               var draggedTagWidth = select(this).node().offsetWidth;
80868
80869               if (field.key === 'destination' || field.key === 'via') {
80870                 // meaning tags are full width
80871                 _container.selectAll('.chip').style('transform', function (d2, index2) {
80872                   var node = select(this).node();
80873
80874                   if (index === index2) {
80875                     return 'translate(' + x + 'px, ' + y + 'px)'; // move the dragged tag up the order
80876                   } else if (index2 > index && d3_event.y > node.offsetTop) {
80877                     if (targetIndex === null || index2 > targetIndex) {
80878                       targetIndex = index2;
80879                     }
80880
80881                     return 'translateY(-100%)'; // move the dragged tag down the order
80882                   } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
80883                     if (targetIndex === null || index2 < targetIndex) {
80884                       targetIndex = index2;
80885                     }
80886
80887                     return 'translateY(100%)';
80888                   }
80889
80890                   return null;
80891                 });
80892               } else {
80893                 _container.selectAll('.chip').each(function (d2, index2) {
80894                   var node = select(this).node(); // check the cursor is in the bounding box
80895
80896                   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) {
80897                     targetIndex = index2;
80898                     targetIndexOffsetTop = node.offsetTop;
80899                   }
80900                 }).style('transform', function (d2, index2) {
80901                   var node = select(this).node();
80902
80903                   if (index === index2) {
80904                     return 'translate(' + x + 'px, ' + y + 'px)';
80905                   } // only translate tags in the same row
80906
80907
80908                   if (node.offsetTop === targetIndexOffsetTop) {
80909                     if (index2 < index && index2 >= targetIndex) {
80910                       return 'translateX(' + draggedTagWidth + 'px)';
80911                     } else if (index2 > index && index2 <= targetIndex) {
80912                       return 'translateX(-' + draggedTagWidth + 'px)';
80913                     }
80914                   }
80915
80916                   return null;
80917                 });
80918               }
80919             }).on('end', function () {
80920               if (!select(this).classed('dragging')) {
80921                 return;
80922               }
80923
80924               var index = selection.nodes().indexOf(this);
80925               select(this).classed('dragging', false);
80926
80927               _container.selectAll('.chip').style('transform', null);
80928
80929               if (typeof targetIndex === 'number') {
80930                 var element = _multiData[index];
80931
80932                 _multiData.splice(index, 1);
80933
80934                 _multiData.splice(targetIndex, 0, element);
80935
80936                 var t = {};
80937
80938                 if (_multiData.length) {
80939                   t[field.key] = _multiData.map(function (element) {
80940                     return element.key;
80941                   }).join(';');
80942                 } else {
80943                   t[field.key] = undefined;
80944                 }
80945
80946                 dispatch.call('change', this, t);
80947               }
80948
80949               dragOrigin = undefined;
80950               targetIndex = undefined;
80951             }));
80952           }
80953
80954           combo.focus = function () {
80955             _input.node().focus();
80956           };
80957
80958           combo.entityIDs = function (val) {
80959             if (!arguments.length) return _entityIDs;
80960             _entityIDs = val;
80961             return combo;
80962           };
80963
80964           function combinedEntityExtent() {
80965             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
80966           }
80967
80968           return utilRebind(combo, dispatch, 'on');
80969         }
80970
80971         function uiFieldText(field, context) {
80972           var dispatch = dispatch$8('change');
80973           var input = select(null);
80974           var outlinkButton = select(null);
80975           var _entityIDs = [];
80976
80977           var _tags;
80978
80979           var _phoneFormats = {};
80980
80981           if (field.type === 'tel') {
80982             _mainFileFetcher.get('phone_formats').then(function (d) {
80983               _phoneFormats = d;
80984               updatePhonePlaceholder();
80985             })["catch"](function () {
80986               /* ignore */
80987             });
80988           }
80989
80990           function calcLocked() {
80991             // Protect certain fields that have a companion `*:wikidata` value
80992             var isLocked = (field.id === 'brand' || field.id === 'network' || field.id === 'operator' || field.id === 'flag') && _entityIDs.length && _entityIDs.some(function (entityID) {
80993               var entity = context.graph().hasEntity(entityID);
80994               if (!entity) return false; // Features linked to Wikidata are likely important and should be protected
80995
80996               if (entity.tags.wikidata) return true;
80997               var preset = _mainPresetIndex.match(entity, context.graph());
80998               var isSuggestion = preset && preset.suggestion; // Lock the field if there is a value and a companion `*:wikidata` value
80999
81000               var which = field.id; // 'brand', 'network', 'operator', 'flag'
81001
81002               return isSuggestion && !!entity.tags[which] && !!entity.tags[which + ':wikidata'];
81003             });
81004
81005             field.locked(isLocked);
81006           }
81007
81008           function i(selection) {
81009             calcLocked();
81010             var isLocked = field.locked();
81011             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81012             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81013             input = wrap.selectAll('input').data([0]);
81014             input = input.enter().append('input').attr('type', field.type === 'identifier' || field.type === 'roadheight' ? 'text' : field.type).attr('id', field.domId).classed(field.type, true).call(utilNoAuto).merge(input);
81015             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
81016
81017             if (field.type === 'tel') {
81018               updatePhonePlaceholder();
81019             } else if (field.type === 'number') {
81020               var rtl = _mainLocalizer.textDirection() === 'rtl';
81021               input.attr('type', 'text');
81022               var inc = field.increment;
81023               var buttons = wrap.selectAll('.increment, .decrement').data(rtl ? [inc, -inc] : [-inc, inc]);
81024               buttons.enter().append('button').attr('class', function (d) {
81025                 var which = d > 0 ? 'increment' : 'decrement';
81026                 return 'form-field-button ' + which;
81027               }).merge(buttons).on('click', function (d3_event, d) {
81028                 d3_event.preventDefault();
81029                 var raw_vals = input.node().value || '0';
81030                 var vals = raw_vals.split(';');
81031                 vals = vals.map(function (v) {
81032                   var num = parseFloat(v.trim(), 10);
81033                   return isFinite(num) ? clamped(num + d) : v.trim();
81034                 });
81035                 input.node().value = vals.join(';');
81036                 change()();
81037               });
81038             } else if (field.type === 'identifier' && field.urlFormat && field.pattern) {
81039               input.attr('type', 'text');
81040               outlinkButton = wrap.selectAll('.foreign-id-permalink').data([0]);
81041               outlinkButton.enter().append('button').call(svgIcon('#iD-icon-out-link')).attr('class', 'form-field-button foreign-id-permalink').attr('title', function () {
81042                 var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
81043
81044                 if (domainResults.length >= 2 && domainResults[1]) {
81045                   var domain = domainResults[1];
81046                   return _t('icons.view_on', {
81047                     domain: domain
81048                   });
81049                 }
81050
81051                 return '';
81052               }).on('click', function (d3_event) {
81053                 d3_event.preventDefault();
81054                 var value = validIdentifierValueForLink();
81055
81056                 if (value) {
81057                   var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
81058                   window.open(url, '_blank');
81059                 }
81060               }).merge(outlinkButton);
81061             }
81062           }
81063
81064           function updatePhonePlaceholder() {
81065             if (input.empty() || !Object.keys(_phoneFormats).length) return;
81066             var extent = combinedEntityExtent();
81067             var countryCode = extent && iso1A2Code(extent.center());
81068
81069             var format = countryCode && _phoneFormats[countryCode.toLowerCase()];
81070
81071             if (format) input.attr('placeholder', format);
81072           }
81073
81074           function validIdentifierValueForLink() {
81075             if (field.type === 'identifier' && field.pattern) {
81076               var value = utilGetSetValue(input).trim().split(';')[0];
81077               return value && value.match(new RegExp(field.pattern));
81078             }
81079
81080             return null;
81081           } // clamp number to min/max
81082
81083
81084           function clamped(num) {
81085             if (field.minValue !== undefined) {
81086               num = Math.max(num, field.minValue);
81087             }
81088
81089             if (field.maxValue !== undefined) {
81090               num = Math.min(num, field.maxValue);
81091             }
81092
81093             return num;
81094           }
81095
81096           function change(onInput) {
81097             return function () {
81098               var t = {};
81099               var val = utilGetSetValue(input);
81100               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
81101
81102               if (!val && Array.isArray(_tags[field.key])) return;
81103
81104               if (!onInput) {
81105                 if (field.type === 'number' && val) {
81106                   var vals = val.split(';');
81107                   vals = vals.map(function (v) {
81108                     var num = parseFloat(v.trim(), 10);
81109                     return isFinite(num) ? clamped(num) : v.trim();
81110                   });
81111                   val = vals.join(';');
81112                 }
81113
81114                 utilGetSetValue(input, val);
81115               }
81116
81117               t[field.key] = val || undefined;
81118               dispatch.call('change', this, t, onInput);
81119             };
81120           }
81121
81122           i.entityIDs = function (val) {
81123             if (!arguments.length) return _entityIDs;
81124             _entityIDs = val;
81125             return i;
81126           };
81127
81128           i.tags = function (tags) {
81129             _tags = tags;
81130             var isMixed = Array.isArray(tags[field.key]);
81131             utilGetSetValue(input, !isMixed && tags[field.key] ? tags[field.key] : '').attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : undefined).attr('placeholder', isMixed ? _t('inspector.multiple_values') : field.placeholder() || _t('inspector.unknown')).classed('mixed', isMixed);
81132
81133             if (outlinkButton && !outlinkButton.empty()) {
81134               var disabled = !validIdentifierValueForLink();
81135               outlinkButton.classed('disabled', disabled);
81136             }
81137           };
81138
81139           i.focus = function () {
81140             var node = input.node();
81141             if (node) node.focus();
81142           };
81143
81144           function combinedEntityExtent() {
81145             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
81146           }
81147
81148           return utilRebind(i, dispatch, 'on');
81149         }
81150
81151         function uiFieldAccess(field, context) {
81152           var dispatch = dispatch$8('change');
81153           var items = select(null);
81154
81155           var _tags;
81156
81157           function access(selection) {
81158             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81159             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81160             var list = wrap.selectAll('ul').data([0]);
81161             list = list.enter().append('ul').attr('class', 'rows').merge(list);
81162             items = list.selectAll('li').data(field.keys); // Enter
81163
81164             var enter = items.enter().append('li').attr('class', function (d) {
81165               return 'labeled-input preset-access-' + d;
81166             });
81167             enter.append('span').attr('class', 'label preset-label-access').attr('for', function (d) {
81168               return 'preset-input-access-' + d;
81169             }).html(function (d) {
81170               return field.t.html('types.' + d);
81171             });
81172             enter.append('div').attr('class', 'preset-input-access-wrap').append('input').attr('type', 'text').attr('class', function (d) {
81173               return 'preset-input-access preset-input-access-' + d;
81174             }).call(utilNoAuto).each(function (d) {
81175               select(this).call(uiCombobox(context, 'access-' + d).data(access.options(d)));
81176             }); // Update
81177
81178             items = items.merge(enter);
81179             wrap.selectAll('.preset-input-access').on('change', change).on('blur', change);
81180           }
81181
81182           function change(d3_event, d) {
81183             var tag = {};
81184             var value = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
81185
81186             if (!value && typeof _tags[d] !== 'string') return;
81187             tag[d] = value || undefined;
81188             dispatch.call('change', this, tag);
81189           }
81190
81191           access.options = function (type) {
81192             var options = ['no', 'permissive', 'private', 'permit', 'destination'];
81193
81194             if (type !== 'access') {
81195               options.unshift('yes');
81196               options.push('designated');
81197
81198               if (type === 'bicycle') {
81199                 options.push('dismount');
81200               }
81201             }
81202
81203             return options.map(function (option) {
81204               return {
81205                 title: field.t('options.' + option + '.description'),
81206                 value: option
81207               };
81208             });
81209           };
81210
81211           var placeholdersByHighway = {
81212             footway: {
81213               foot: 'designated',
81214               motor_vehicle: 'no'
81215             },
81216             steps: {
81217               foot: 'yes',
81218               motor_vehicle: 'no',
81219               bicycle: 'no',
81220               horse: 'no'
81221             },
81222             pedestrian: {
81223               foot: 'yes',
81224               motor_vehicle: 'no'
81225             },
81226             cycleway: {
81227               motor_vehicle: 'no',
81228               bicycle: 'designated'
81229             },
81230             bridleway: {
81231               motor_vehicle: 'no',
81232               horse: 'designated'
81233             },
81234             path: {
81235               foot: 'yes',
81236               motor_vehicle: 'no',
81237               bicycle: 'yes',
81238               horse: 'yes'
81239             },
81240             motorway: {
81241               foot: 'no',
81242               motor_vehicle: 'yes',
81243               bicycle: 'no',
81244               horse: 'no'
81245             },
81246             trunk: {
81247               motor_vehicle: 'yes'
81248             },
81249             primary: {
81250               foot: 'yes',
81251               motor_vehicle: 'yes',
81252               bicycle: 'yes',
81253               horse: 'yes'
81254             },
81255             secondary: {
81256               foot: 'yes',
81257               motor_vehicle: 'yes',
81258               bicycle: 'yes',
81259               horse: 'yes'
81260             },
81261             tertiary: {
81262               foot: 'yes',
81263               motor_vehicle: 'yes',
81264               bicycle: 'yes',
81265               horse: 'yes'
81266             },
81267             residential: {
81268               foot: 'yes',
81269               motor_vehicle: 'yes',
81270               bicycle: 'yes',
81271               horse: 'yes'
81272             },
81273             unclassified: {
81274               foot: 'yes',
81275               motor_vehicle: 'yes',
81276               bicycle: 'yes',
81277               horse: 'yes'
81278             },
81279             service: {
81280               foot: 'yes',
81281               motor_vehicle: 'yes',
81282               bicycle: 'yes',
81283               horse: 'yes'
81284             },
81285             motorway_link: {
81286               foot: 'no',
81287               motor_vehicle: 'yes',
81288               bicycle: 'no',
81289               horse: 'no'
81290             },
81291             trunk_link: {
81292               motor_vehicle: 'yes'
81293             },
81294             primary_link: {
81295               foot: 'yes',
81296               motor_vehicle: 'yes',
81297               bicycle: 'yes',
81298               horse: 'yes'
81299             },
81300             secondary_link: {
81301               foot: 'yes',
81302               motor_vehicle: 'yes',
81303               bicycle: 'yes',
81304               horse: 'yes'
81305             },
81306             tertiary_link: {
81307               foot: 'yes',
81308               motor_vehicle: 'yes',
81309               bicycle: 'yes',
81310               horse: 'yes'
81311             }
81312           };
81313
81314           access.tags = function (tags) {
81315             _tags = tags;
81316             utilGetSetValue(items.selectAll('.preset-input-access'), function (d) {
81317               return typeof tags[d] === 'string' ? tags[d] : '';
81318             }).classed('mixed', function (d) {
81319               return tags[d] && Array.isArray(tags[d]);
81320             }).attr('title', function (d) {
81321               return tags[d] && Array.isArray(tags[d]) && tags[d].filter(Boolean).join('\n');
81322             }).attr('placeholder', function (d) {
81323               if (tags[d] && Array.isArray(tags[d])) {
81324                 return _t('inspector.multiple_values');
81325               }
81326
81327               if (d === 'access') {
81328                 return 'yes';
81329               }
81330
81331               if (tags.access && typeof tags.access === 'string') {
81332                 return tags.access;
81333               }
81334
81335               if (tags.highway) {
81336                 if (typeof tags.highway === 'string') {
81337                   if (placeholdersByHighway[tags.highway] && placeholdersByHighway[tags.highway][d]) {
81338                     return placeholdersByHighway[tags.highway][d];
81339                   }
81340                 } else {
81341                   var impliedAccesses = tags.highway.filter(Boolean).map(function (highwayVal) {
81342                     return placeholdersByHighway[highwayVal] && placeholdersByHighway[highwayVal][d];
81343                   }).filter(Boolean);
81344
81345                   if (impliedAccesses.length === tags.highway.length && new Set(impliedAccesses).size === 1) {
81346                     // if all the highway values have the same implied access for this type then use that
81347                     return impliedAccesses[0];
81348                   }
81349                 }
81350               }
81351
81352               return field.placeholder();
81353             });
81354           };
81355
81356           access.focus = function () {
81357             items.selectAll('.preset-input-access').node().focus();
81358           };
81359
81360           return utilRebind(access, dispatch, 'on');
81361         }
81362
81363         function uiFieldAddress(field, context) {
81364           var dispatch = dispatch$8('change');
81365
81366           var _selection = select(null);
81367
81368           var _wrap = select(null);
81369
81370           var addrField = _mainPresetIndex.field('address'); // needed for placeholder strings
81371
81372           var _entityIDs = [];
81373
81374           var _tags;
81375
81376           var _countryCode;
81377
81378           var _addressFormats = [{
81379             format: [['housenumber', 'street'], ['city', 'postcode']]
81380           }];
81381           _mainFileFetcher.get('address_formats').then(function (d) {
81382             _addressFormats = d;
81383
81384             if (!_selection.empty()) {
81385               _selection.call(address);
81386             }
81387           })["catch"](function () {
81388             /* ignore */
81389           });
81390
81391           function getNearStreets() {
81392             var extent = combinedEntityExtent();
81393             var l = extent.center();
81394             var box = geoExtent(l).padByMeters(200);
81395             var streets = context.history().intersects(box).filter(isAddressable).map(function (d) {
81396               var loc = context.projection([(extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2]);
81397               var choice = geoChooseEdge(context.graph().childNodes(d), loc, context.projection);
81398               return {
81399                 title: d.tags.name,
81400                 value: d.tags.name,
81401                 dist: choice.distance
81402               };
81403             }).sort(function (a, b) {
81404               return a.dist - b.dist;
81405             });
81406             return utilArrayUniqBy(streets, 'value');
81407
81408             function isAddressable(d) {
81409               return d.tags.highway && d.tags.name && d.type === 'way';
81410             }
81411           }
81412
81413           function getNearCities() {
81414             var extent = combinedEntityExtent();
81415             var l = extent.center();
81416             var box = geoExtent(l).padByMeters(200);
81417             var cities = context.history().intersects(box).filter(isAddressable).map(function (d) {
81418               return {
81419                 title: d.tags['addr:city'] || d.tags.name,
81420                 value: d.tags['addr:city'] || d.tags.name,
81421                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
81422               };
81423             }).sort(function (a, b) {
81424               return a.dist - b.dist;
81425             });
81426             return utilArrayUniqBy(cities, 'value');
81427
81428             function isAddressable(d) {
81429               if (d.tags.name) {
81430                 if (d.tags.admin_level === '8' && d.tags.boundary === 'administrative') return true;
81431                 if (d.tags.border_type === 'city') return true;
81432                 if (d.tags.place === 'city' || d.tags.place === 'town' || d.tags.place === 'village') return true;
81433               }
81434
81435               if (d.tags['addr:city']) return true;
81436               return false;
81437             }
81438           }
81439
81440           function getNearValues(key) {
81441             var extent = combinedEntityExtent();
81442             var l = extent.center();
81443             var box = geoExtent(l).padByMeters(200);
81444             var results = context.history().intersects(box).filter(function hasTag(d) {
81445               return _entityIDs.indexOf(d.id) === -1 && d.tags[key];
81446             }).map(function (d) {
81447               return {
81448                 title: d.tags[key],
81449                 value: d.tags[key],
81450                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
81451               };
81452             }).sort(function (a, b) {
81453               return a.dist - b.dist;
81454             });
81455             return utilArrayUniqBy(results, 'value');
81456           }
81457
81458           function updateForCountryCode() {
81459             if (!_countryCode) return;
81460             var addressFormat;
81461
81462             for (var i = 0; i < _addressFormats.length; i++) {
81463               var format = _addressFormats[i];
81464
81465               if (!format.countryCodes) {
81466                 addressFormat = format; // choose the default format, keep going
81467               } else if (format.countryCodes.indexOf(_countryCode) !== -1) {
81468                 addressFormat = format; // choose the country format, stop here
81469
81470                 break;
81471               }
81472             }
81473
81474             var dropdowns = addressFormat.dropdowns || ['city', 'county', 'country', 'district', 'hamlet', 'neighbourhood', 'place', 'postcode', 'province', 'quarter', 'state', 'street', 'subdistrict', 'suburb'];
81475             var widths = addressFormat.widths || {
81476               housenumber: 1 / 3,
81477               street: 2 / 3,
81478               city: 2 / 3,
81479               state: 1 / 4,
81480               postcode: 1 / 3
81481             };
81482
81483             function row(r) {
81484               // Normalize widths.
81485               var total = r.reduce(function (sum, key) {
81486                 return sum + (widths[key] || 0.5);
81487               }, 0);
81488               return r.map(function (key) {
81489                 return {
81490                   id: key,
81491                   width: (widths[key] || 0.5) / total
81492                 };
81493               });
81494             }
81495
81496             var rows = _wrap.selectAll('.addr-row').data(addressFormat.format, function (d) {
81497               return d.toString();
81498             });
81499
81500             rows.exit().remove();
81501             rows.enter().append('div').attr('class', 'addr-row').selectAll('input').data(row).enter().append('input').property('type', 'text').call(updatePlaceholder).attr('class', function (d) {
81502               return 'addr-' + d.id;
81503             }).call(utilNoAuto).each(addDropdown).style('width', function (d) {
81504               return d.width * 100 + '%';
81505             });
81506
81507             function addDropdown(d) {
81508               if (dropdowns.indexOf(d.id) === -1) return; // not a dropdown
81509
81510               var nearValues = d.id === 'street' ? getNearStreets : d.id === 'city' ? getNearCities : getNearValues;
81511               select(this).call(uiCombobox(context, 'address-' + d.id).minItems(1).caseSensitive(true).fetcher(function (value, callback) {
81512                 callback(nearValues('addr:' + d.id));
81513               }));
81514             }
81515
81516             _wrap.selectAll('input').on('blur', change()).on('change', change());
81517
81518             _wrap.selectAll('input:not(.combobox-input)').on('input', change(true));
81519
81520             if (_tags) updateTags(_tags);
81521           }
81522
81523           function address(selection) {
81524             _selection = selection;
81525             _wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81526             _wrap = _wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(_wrap);
81527             var extent = combinedEntityExtent();
81528
81529             if (extent) {
81530               var countryCode;
81531
81532               if (context.inIntro()) {
81533                 // localize the address format for the walkthrough
81534                 countryCode = _t('intro.graph.countrycode');
81535               } else {
81536                 var center = extent.center();
81537                 countryCode = iso1A2Code(center);
81538               }
81539
81540               if (countryCode) {
81541                 _countryCode = countryCode.toLowerCase();
81542                 updateForCountryCode();
81543               }
81544             }
81545           }
81546
81547           function change(onInput) {
81548             return function () {
81549               var tags = {};
81550
81551               _wrap.selectAll('input').each(function (subfield) {
81552                 var key = field.key + ':' + subfield.id;
81553                 var value = this.value;
81554                 if (!onInput) value = context.cleanTagValue(value); // don't override multiple values with blank string
81555
81556                 if (Array.isArray(_tags[key]) && !value) return;
81557                 tags[key] = value || undefined;
81558               });
81559
81560               dispatch.call('change', this, tags, onInput);
81561             };
81562           }
81563
81564           function updatePlaceholder(inputSelection) {
81565             return inputSelection.attr('placeholder', function (subfield) {
81566               if (_tags && Array.isArray(_tags[field.key + ':' + subfield.id])) {
81567                 return _t('inspector.multiple_values');
81568               }
81569
81570               if (_countryCode) {
81571                 var localkey = subfield.id + '!' + _countryCode;
81572                 var tkey = addrField.hasTextForStringId('placeholders.' + localkey) ? localkey : subfield.id;
81573                 return addrField.t('placeholders.' + tkey);
81574               }
81575             });
81576           }
81577
81578           function updateTags(tags) {
81579             utilGetSetValue(_wrap.selectAll('input'), function (subfield) {
81580               var val = tags[field.key + ':' + subfield.id];
81581               return typeof val === 'string' ? val : '';
81582             }).attr('title', function (subfield) {
81583               var val = tags[field.key + ':' + subfield.id];
81584               return val && Array.isArray(val) && val.filter(Boolean).join('\n');
81585             }).classed('mixed', function (subfield) {
81586               return Array.isArray(tags[field.key + ':' + subfield.id]);
81587             }).call(updatePlaceholder);
81588           }
81589
81590           function combinedEntityExtent() {
81591             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
81592           }
81593
81594           address.entityIDs = function (val) {
81595             if (!arguments.length) return _entityIDs;
81596             _entityIDs = val;
81597             return address;
81598           };
81599
81600           address.tags = function (tags) {
81601             _tags = tags;
81602             updateTags(tags);
81603           };
81604
81605           address.focus = function () {
81606             var node = _wrap.selectAll('input').node();
81607
81608             if (node) node.focus();
81609           };
81610
81611           return utilRebind(address, dispatch, 'on');
81612         }
81613
81614         function uiFieldCycleway(field, context) {
81615           var dispatch = dispatch$8('change');
81616           var items = select(null);
81617           var wrap = select(null);
81618
81619           var _tags;
81620
81621           function cycleway(selection) {
81622             function stripcolon(s) {
81623               return s.replace(':', '');
81624             }
81625
81626             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81627             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81628             var div = wrap.selectAll('ul').data([0]);
81629             div = div.enter().append('ul').attr('class', 'rows').merge(div);
81630             var keys = ['cycleway:left', 'cycleway:right'];
81631             items = div.selectAll('li').data(keys);
81632             var enter = items.enter().append('li').attr('class', function (d) {
81633               return 'labeled-input preset-cycleway-' + stripcolon(d);
81634             });
81635             enter.append('span').attr('class', 'label preset-label-cycleway').attr('for', function (d) {
81636               return 'preset-input-cycleway-' + stripcolon(d);
81637             }).html(function (d) {
81638               return field.t.html('types.' + d);
81639             });
81640             enter.append('div').attr('class', 'preset-input-cycleway-wrap').append('input').attr('type', 'text').attr('class', function (d) {
81641               return 'preset-input-cycleway preset-input-' + stripcolon(d);
81642             }).call(utilNoAuto).each(function (d) {
81643               select(this).call(uiCombobox(context, 'cycleway-' + stripcolon(d)).data(cycleway.options(d)));
81644             });
81645             items = items.merge(enter); // Update
81646
81647             wrap.selectAll('.preset-input-cycleway').on('change', change).on('blur', change);
81648           }
81649
81650           function change(d3_event, key) {
81651             var newValue = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
81652
81653             if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return;
81654
81655             if (newValue === 'none' || newValue === '') {
81656               newValue = undefined;
81657             }
81658
81659             var otherKey = key === 'cycleway:left' ? 'cycleway:right' : 'cycleway:left';
81660             var otherValue = typeof _tags.cycleway === 'string' ? _tags.cycleway : _tags[otherKey];
81661
81662             if (otherValue && Array.isArray(otherValue)) {
81663               // we must always have an explicit value for comparison
81664               otherValue = otherValue[0];
81665             }
81666
81667             if (otherValue === 'none' || otherValue === '') {
81668               otherValue = undefined;
81669             }
81670
81671             var tag = {}; // If the left and right tags match, use the cycleway tag to tag both
81672             // sides the same way
81673
81674             if (newValue === otherValue) {
81675               tag = {
81676                 cycleway: newValue,
81677                 'cycleway:left': undefined,
81678                 'cycleway:right': undefined
81679               };
81680             } else {
81681               // Always set both left and right as changing one can affect the other
81682               tag = {
81683                 cycleway: undefined
81684               };
81685               tag[key] = newValue;
81686               tag[otherKey] = otherValue;
81687             }
81688
81689             dispatch.call('change', this, tag);
81690           }
81691
81692           cycleway.options = function () {
81693             return field.options.map(function (option) {
81694               return {
81695                 title: field.t('options.' + option + '.description'),
81696                 value: option
81697               };
81698             });
81699           };
81700
81701           cycleway.tags = function (tags) {
81702             _tags = tags; // If cycleway is set, use that instead of individual values
81703
81704             var commonValue = typeof tags.cycleway === 'string' && tags.cycleway;
81705             utilGetSetValue(items.selectAll('.preset-input-cycleway'), function (d) {
81706               if (commonValue) return commonValue;
81707               return !tags.cycleway && typeof tags[d] === 'string' ? tags[d] : '';
81708             }).attr('title', function (d) {
81709               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
81710                 var vals = [];
81711
81712                 if (Array.isArray(tags.cycleway)) {
81713                   vals = vals.concat(tags.cycleway);
81714                 }
81715
81716                 if (Array.isArray(tags[d])) {
81717                   vals = vals.concat(tags[d]);
81718                 }
81719
81720                 return vals.filter(Boolean).join('\n');
81721               }
81722
81723               return null;
81724             }).attr('placeholder', function (d) {
81725               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
81726                 return _t('inspector.multiple_values');
81727               }
81728
81729               return field.placeholder();
81730             }).classed('mixed', function (d) {
81731               return Array.isArray(tags.cycleway) || Array.isArray(tags[d]);
81732             });
81733           };
81734
81735           cycleway.focus = function () {
81736             var node = wrap.selectAll('input').node();
81737             if (node) node.focus();
81738           };
81739
81740           return utilRebind(cycleway, dispatch, 'on');
81741         }
81742
81743         function uiFieldLanes(field, context) {
81744           var dispatch = dispatch$8('change');
81745           var LANE_WIDTH = 40;
81746           var LANE_HEIGHT = 200;
81747           var _entityIDs = [];
81748
81749           function lanes(selection) {
81750             var lanesData = context.entity(_entityIDs[0]).lanes();
81751
81752             if (!context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
81753               selection.call(lanes.off);
81754               return;
81755             }
81756
81757             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81758             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81759             var surface = wrap.selectAll('.surface').data([0]);
81760             var d = utilGetDimensions(wrap);
81761             var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
81762             surface = surface.enter().append('svg').attr('width', d[0]).attr('height', 300).attr('class', 'surface').merge(surface);
81763             var lanesSelection = surface.selectAll('.lanes').data([0]);
81764             lanesSelection = lanesSelection.enter().append('g').attr('class', 'lanes').merge(lanesSelection);
81765             lanesSelection.attr('transform', function () {
81766               return 'translate(' + freeSpace / 2 + ', 0)';
81767             });
81768             var lane = lanesSelection.selectAll('.lane').data(lanesData.lanes);
81769             lane.exit().remove();
81770             var enter = lane.enter().append('g').attr('class', 'lane');
81771             enter.append('g').append('rect').attr('y', 50).attr('width', LANE_WIDTH).attr('height', LANE_HEIGHT);
81772             enter.append('g').attr('class', 'forward').append('text').attr('y', 40).attr('x', 14).html('▲');
81773             enter.append('g').attr('class', 'bothways').append('text').attr('y', 40).attr('x', 14).html('▲▼');
81774             enter.append('g').attr('class', 'backward').append('text').attr('y', 40).attr('x', 14).html('▼');
81775             lane = lane.merge(enter);
81776             lane.attr('transform', function (d) {
81777               return 'translate(' + LANE_WIDTH * d.index * 1.5 + ', 0)';
81778             });
81779             lane.select('.forward').style('visibility', function (d) {
81780               return d.direction === 'forward' ? 'visible' : 'hidden';
81781             });
81782             lane.select('.bothways').style('visibility', function (d) {
81783               return d.direction === 'bothways' ? 'visible' : 'hidden';
81784             });
81785             lane.select('.backward').style('visibility', function (d) {
81786               return d.direction === 'backward' ? 'visible' : 'hidden';
81787             });
81788           }
81789
81790           lanes.entityIDs = function (val) {
81791             _entityIDs = val;
81792           };
81793
81794           lanes.tags = function () {};
81795
81796           lanes.focus = function () {};
81797
81798           lanes.off = function () {};
81799
81800           return utilRebind(lanes, dispatch, 'on');
81801         }
81802         uiFieldLanes.supportsMultiselection = false;
81803
81804         var _languagesArray = [];
81805         function uiFieldLocalized(field, context) {
81806           var dispatch = dispatch$8('change', 'input');
81807           var wikipedia = services.wikipedia;
81808           var input = select(null);
81809           var localizedInputs = select(null);
81810
81811           var _countryCode;
81812
81813           var _tags; // A concern here in switching to async data means that _languagesArray will not
81814           // be available the first time through, so things like the fetchers and
81815           // the language() function will not work immediately.
81816
81817
81818           _mainFileFetcher.get('languages').then(loadLanguagesArray)["catch"](function () {
81819             /* ignore */
81820           });
81821           var _territoryLanguages = {};
81822           _mainFileFetcher.get('territory_languages').then(function (d) {
81823             _territoryLanguages = d;
81824           })["catch"](function () {
81825             /* ignore */
81826           }); // reuse these combos
81827
81828           var langCombo = uiCombobox(context, 'localized-lang').fetcher(fetchLanguages).minItems(0);
81829
81830           var _selection = select(null);
81831
81832           var _multilingual = [];
81833
81834           var _buttonTip = uiTooltip().title(_t.html('translate.translate')).placement('left');
81835
81836           var _wikiTitles;
81837
81838           var _entityIDs = [];
81839
81840           function loadLanguagesArray(dataLanguages) {
81841             if (_languagesArray.length !== 0) return; // some conversion is needed to ensure correct OSM tags are used
81842
81843             var replacements = {
81844               sr: 'sr-Cyrl',
81845               // in OSM, `sr` implies Cyrillic
81846               'sr-Cyrl': false // `sr-Cyrl` isn't used in OSM
81847
81848             };
81849
81850             for (var code in dataLanguages) {
81851               if (replacements[code] === false) continue;
81852               var metaCode = code;
81853               if (replacements[code]) metaCode = replacements[code];
81854
81855               _languagesArray.push({
81856                 localName: _mainLocalizer.languageName(metaCode, {
81857                   localOnly: true
81858                 }),
81859                 nativeName: dataLanguages[metaCode].nativeName,
81860                 code: code,
81861                 label: _mainLocalizer.languageName(metaCode)
81862               });
81863             }
81864           }
81865
81866           function calcLocked() {
81867             // Protect name field for suggestion presets that don't display a brand/operator field
81868             var isLocked = field.id === 'name' && _entityIDs.length && _entityIDs.some(function (entityID) {
81869               var entity = context.graph().hasEntity(entityID);
81870               if (!entity) return false; // Features linked to Wikidata are likely important and should be protected
81871
81872               if (entity.tags.wikidata) return true; // Assume the name has already been confirmed if its source has been researched
81873
81874               if (entity.tags['name:etymology:wikidata']) return true; // Lock the `name` if this is a suggestion preset that assigns the name,
81875               // and the preset does not display a `brand` or `operator` field.
81876               // (For presets like hotels, car dealerships, post offices, the `name` should remain editable)
81877               // see also similar logic in `outdated_tags.js`
81878
81879               var preset = _mainPresetIndex.match(entity, context.graph());
81880
81881               if (preset) {
81882                 var isSuggestion = preset.suggestion;
81883                 var fields = preset.fields();
81884                 var showsBrandField = fields.some(function (d) {
81885                   return d.id === 'brand';
81886                 });
81887                 var showsOperatorField = fields.some(function (d) {
81888                   return d.id === 'operator';
81889                 });
81890                 var setsName = preset.addTags.name;
81891                 var setsBrandWikidata = preset.addTags['brand:wikidata'];
81892                 var setsOperatorWikidata = preset.addTags['operator:wikidata'];
81893                 return isSuggestion && setsName && (setsBrandWikidata && !showsBrandField || setsOperatorWikidata && !showsOperatorField);
81894               }
81895
81896               return false;
81897             });
81898
81899             field.locked(isLocked);
81900           } // update _multilingual, maintaining the existing order
81901
81902
81903           function calcMultilingual(tags) {
81904             var existingLangsOrdered = _multilingual.map(function (item) {
81905               return item.lang;
81906             });
81907
81908             var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
81909
81910             for (var k in tags) {
81911               var m = k.match(/^(.*):(.*)$/);
81912
81913               if (m && m[1] === field.key && m[2]) {
81914                 var item = {
81915                   lang: m[2],
81916                   value: tags[k]
81917                 };
81918
81919                 if (existingLangs.has(item.lang)) {
81920                   // update the value
81921                   _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
81922                   existingLangs["delete"](item.lang);
81923                 } else {
81924                   _multilingual.push(item);
81925                 }
81926               }
81927             } // Don't remove items based on deleted tags, since this makes the UI
81928             // disappear unexpectedly when clearing values - #8164
81929
81930
81931             _multilingual.forEach(function (item) {
81932               if (item.lang && existingLangs.has(item.lang)) {
81933                 item.value = '';
81934               }
81935             });
81936           }
81937
81938           function localized(selection) {
81939             _selection = selection;
81940             calcLocked();
81941             var isLocked = field.locked();
81942             var wrap = selection.selectAll('.form-field-input-wrap').data([0]); // enter/update
81943
81944             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81945             input = wrap.selectAll('.localized-main').data([0]); // enter/update
81946
81947             input = input.enter().append('input').attr('type', 'text').attr('id', field.domId).attr('class', 'localized-main').call(utilNoAuto).merge(input);
81948             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
81949             var translateButton = wrap.selectAll('.localized-add').data([0]);
81950             translateButton = translateButton.enter().append('button').attr('class', 'localized-add form-field-button').call(svgIcon('#iD-icon-plus')).merge(translateButton);
81951             translateButton.classed('disabled', !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on('click', addNew);
81952
81953             if (_tags && !_multilingual.length) {
81954               calcMultilingual(_tags);
81955             }
81956
81957             localizedInputs = selection.selectAll('.localized-multilingual').data([0]);
81958             localizedInputs = localizedInputs.enter().append('div').attr('class', 'localized-multilingual').merge(localizedInputs);
81959             localizedInputs.call(renderMultilingual);
81960             localizedInputs.selectAll('button, input').classed('disabled', !!isLocked).attr('readonly', isLocked || null);
81961
81962             function addNew(d3_event) {
81963               d3_event.preventDefault();
81964               if (field.locked()) return;
81965               var defaultLang = _mainLocalizer.languageCode().toLowerCase();
81966
81967               var langExists = _multilingual.find(function (datum) {
81968                 return datum.lang === defaultLang;
81969               });
81970
81971               var isLangEn = defaultLang.indexOf('en') > -1;
81972
81973               if (isLangEn || langExists) {
81974                 defaultLang = '';
81975                 langExists = _multilingual.find(function (datum) {
81976                   return datum.lang === defaultLang;
81977                 });
81978               }
81979
81980               if (!langExists) {
81981                 // prepend the value so it appears at the top
81982                 _multilingual.unshift({
81983                   lang: defaultLang,
81984                   value: ''
81985                 });
81986
81987                 localizedInputs.call(renderMultilingual);
81988               }
81989             }
81990
81991             function change(onInput) {
81992               return function (d3_event) {
81993                 if (field.locked()) {
81994                   d3_event.preventDefault();
81995                   return;
81996                 }
81997
81998                 var val = utilGetSetValue(select(this));
81999                 if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
82000
82001                 if (!val && Array.isArray(_tags[field.key])) return;
82002                 var t = {};
82003                 t[field.key] = val || undefined;
82004                 dispatch.call('change', this, t, onInput);
82005               };
82006             }
82007           }
82008
82009           function key(lang) {
82010             return field.key + ':' + lang;
82011           }
82012
82013           function changeLang(d3_event, d) {
82014             var tags = {}; // make sure unrecognized suffixes are lowercase - #7156
82015
82016             var lang = utilGetSetValue(select(this)).toLowerCase();
82017
82018             var language = _languagesArray.find(function (d) {
82019               return d.label.toLowerCase() === lang || d.localName && d.localName.toLowerCase() === lang || d.nativeName && d.nativeName.toLowerCase() === lang;
82020             });
82021
82022             if (language) lang = language.code;
82023
82024             if (d.lang && d.lang !== lang) {
82025               tags[key(d.lang)] = undefined;
82026             }
82027
82028             var newKey = lang && context.cleanTagKey(key(lang));
82029             var value = utilGetSetValue(select(this.parentNode).selectAll('.localized-value'));
82030
82031             if (newKey && value) {
82032               tags[newKey] = value;
82033             } else if (newKey && _wikiTitles && _wikiTitles[d.lang]) {
82034               tags[newKey] = _wikiTitles[d.lang];
82035             }
82036
82037             d.lang = lang;
82038             dispatch.call('change', this, tags);
82039           }
82040
82041           function changeValue(d3_event, d) {
82042             if (!d.lang) return;
82043             var value = context.cleanTagValue(utilGetSetValue(select(this))) || undefined; // don't override multiple values with blank string
82044
82045             if (!value && Array.isArray(d.value)) return;
82046             var t = {};
82047             t[key(d.lang)] = value;
82048             d.value = value;
82049             dispatch.call('change', this, t);
82050           }
82051
82052           function fetchLanguages(value, cb) {
82053             var v = value.toLowerCase(); // show the user's language first
82054
82055             var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
82056
82057             if (_countryCode && _territoryLanguages[_countryCode]) {
82058               langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
82059             }
82060
82061             var langItems = [];
82062             langCodes.forEach(function (code) {
82063               var langItem = _languagesArray.find(function (item) {
82064                 return item.code === code;
82065               });
82066
82067               if (langItem) langItems.push(langItem);
82068             });
82069             langItems = utilArrayUniq(langItems.concat(_languagesArray));
82070             cb(langItems.filter(function (d) {
82071               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;
82072             }).map(function (d) {
82073               return {
82074                 value: d.label
82075               };
82076             }));
82077           }
82078
82079           function renderMultilingual(selection) {
82080             var entries = selection.selectAll('div.entry').data(_multilingual, function (d) {
82081               return d.lang;
82082             });
82083             entries.exit().style('top', '0').style('max-height', '240px').transition().duration(200).style('opacity', '0').style('max-height', '0px').remove();
82084             var entriesEnter = entries.enter().append('div').attr('class', 'entry').each(function (_, index) {
82085               var wrap = select(this);
82086               var domId = utilUniqueDomId(index);
82087               var label = wrap.append('label').attr('class', 'field-label').attr('for', domId);
82088               var text = label.append('span').attr('class', 'label-text');
82089               text.append('span').attr('class', 'label-textvalue').html(_t.html('translate.localized_translation_label'));
82090               text.append('span').attr('class', 'label-textannotation');
82091               label.append('button').attr('class', 'remove-icon-multilingual').on('click', function (d3_event, d) {
82092                 if (field.locked()) return;
82093                 d3_event.preventDefault(); // remove the UI item manually
82094
82095                 _multilingual.splice(_multilingual.indexOf(d), 1);
82096
82097                 var langKey = d.lang && key(d.lang);
82098
82099                 if (langKey && langKey in _tags) {
82100                   delete _tags[langKey]; // remove from entity tags
82101
82102                   var t = {};
82103                   t[langKey] = undefined;
82104                   dispatch.call('change', this, t);
82105                   return;
82106                 }
82107
82108                 renderMultilingual(selection);
82109               }).call(svgIcon('#iD-operation-delete'));
82110               wrap.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);
82111               wrap.append('input').attr('type', 'text').attr('class', 'localized-value').on('blur', changeValue).on('change', changeValue);
82112             });
82113             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 () {
82114               select(this).style('max-height', '').style('overflow', 'visible');
82115             });
82116             entries = entries.merge(entriesEnter);
82117             entries.order(); // allow removing the entry UIs even if there isn't a tag to remove
82118
82119             entries.classed('present', true);
82120             utilGetSetValue(entries.select('.localized-lang'), function (d) {
82121               var langItem = _languagesArray.find(function (item) {
82122                 return item.code === d.lang;
82123               });
82124
82125               if (langItem) return langItem.label;
82126               return d.lang;
82127             });
82128             utilGetSetValue(entries.select('.localized-value'), function (d) {
82129               return typeof d.value === 'string' ? d.value : '';
82130             }).attr('title', function (d) {
82131               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : null;
82132             }).attr('placeholder', function (d) {
82133               return Array.isArray(d.value) ? _t('inspector.multiple_values') : _t('translate.localized_translation_name');
82134             }).classed('mixed', function (d) {
82135               return Array.isArray(d.value);
82136             });
82137           }
82138
82139           localized.tags = function (tags) {
82140             _tags = tags; // Fetch translations from wikipedia
82141
82142             if (typeof tags.wikipedia === 'string' && !_wikiTitles) {
82143               _wikiTitles = {};
82144               var wm = tags.wikipedia.match(/([^:]+):(.+)/);
82145
82146               if (wm && wm[0] && wm[1]) {
82147                 wikipedia.translations(wm[1], wm[2], function (err, d) {
82148                   if (err || !d) return;
82149                   _wikiTitles = d;
82150                 });
82151               }
82152             }
82153
82154             var isMixed = Array.isArray(tags[field.key]);
82155             utilGetSetValue(input, typeof tags[field.key] === 'string' ? tags[field.key] : '').attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : undefined).attr('placeholder', isMixed ? _t('inspector.multiple_values') : field.placeholder()).classed('mixed', isMixed);
82156             calcMultilingual(tags);
82157
82158             _selection.call(localized);
82159           };
82160
82161           localized.focus = function () {
82162             input.node().focus();
82163           };
82164
82165           localized.entityIDs = function (val) {
82166             if (!arguments.length) return _entityIDs;
82167             _entityIDs = val;
82168             _multilingual = [];
82169             loadCountryCode();
82170             return localized;
82171           };
82172
82173           function loadCountryCode() {
82174             var extent = combinedEntityExtent();
82175             var countryCode = extent && iso1A2Code(extent.center());
82176             _countryCode = countryCode && countryCode.toLowerCase();
82177           }
82178
82179           function combinedEntityExtent() {
82180             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
82181           }
82182
82183           return utilRebind(localized, dispatch, 'on');
82184         }
82185
82186         function uiFieldRoadspeed(field, context) {
82187           var dispatch = dispatch$8('change');
82188           var unitInput = select(null);
82189           var input = select(null);
82190           var _entityIDs = [];
82191
82192           var _tags;
82193
82194           var _isImperial;
82195
82196           var speedCombo = uiCombobox(context, 'roadspeed');
82197           var unitCombo = uiCombobox(context, 'roadspeed-unit').data(['km/h', 'mph'].map(comboValues));
82198           var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
82199           var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
82200
82201           function roadspeed(selection) {
82202             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
82203             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
82204             input = wrap.selectAll('input.roadspeed-number').data([0]);
82205             input = input.enter().append('input').attr('type', 'text').attr('class', 'roadspeed-number').attr('id', field.domId).call(utilNoAuto).call(speedCombo).merge(input);
82206             input.on('change', change).on('blur', change);
82207             var loc = combinedEntityExtent().center();
82208             _isImperial = roadSpeedUnit(loc) === 'mph';
82209             unitInput = wrap.selectAll('input.roadspeed-unit').data([0]);
82210             unitInput = unitInput.enter().append('input').attr('type', 'text').attr('class', 'roadspeed-unit').call(unitCombo).merge(unitInput);
82211             unitInput.on('blur', changeUnits).on('change', changeUnits);
82212
82213             function changeUnits() {
82214               _isImperial = utilGetSetValue(unitInput) === 'mph';
82215               utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
82216               setUnitSuggestions();
82217               change();
82218             }
82219           }
82220
82221           function setUnitSuggestions() {
82222             speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
82223             utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
82224           }
82225
82226           function comboValues(d) {
82227             return {
82228               value: d.toString(),
82229               title: d.toString()
82230             };
82231           }
82232
82233           function change() {
82234             var tag = {};
82235             var value = utilGetSetValue(input).trim(); // don't override multiple values with blank string
82236
82237             if (!value && Array.isArray(_tags[field.key])) return;
82238
82239             if (!value) {
82240               tag[field.key] = undefined;
82241             } else if (isNaN(value) || !_isImperial) {
82242               tag[field.key] = context.cleanTagValue(value);
82243             } else {
82244               tag[field.key] = context.cleanTagValue(value + ' mph');
82245             }
82246
82247             dispatch.call('change', this, tag);
82248           }
82249
82250           roadspeed.tags = function (tags) {
82251             _tags = tags;
82252             var value = tags[field.key];
82253             var isMixed = Array.isArray(value);
82254
82255             if (!isMixed) {
82256               if (value && value.indexOf('mph') >= 0) {
82257                 value = parseInt(value, 10).toString();
82258                 _isImperial = true;
82259               } else if (value) {
82260                 _isImperial = false;
82261               }
82262             }
82263
82264             setUnitSuggestions();
82265             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);
82266           };
82267
82268           roadspeed.focus = function () {
82269             input.node().focus();
82270           };
82271
82272           roadspeed.entityIDs = function (val) {
82273             _entityIDs = val;
82274           };
82275
82276           function combinedEntityExtent() {
82277             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
82278           }
82279
82280           return utilRebind(roadspeed, dispatch, 'on');
82281         }
82282
82283         function uiFieldRadio(field, context) {
82284           var dispatch = dispatch$8('change');
82285           var placeholder = select(null);
82286           var wrap = select(null);
82287           var labels = select(null);
82288           var radios = select(null);
82289           var radioData = (field.options || field.keys).slice(); // shallow copy
82290
82291           var typeField;
82292           var layerField;
82293           var _oldType = {};
82294           var _entityIDs = [];
82295
82296           function selectedKey() {
82297             var node = wrap.selectAll('.form-field-input-radio label.active input');
82298             return !node.empty() && node.datum();
82299           }
82300
82301           function radio(selection) {
82302             selection.classed('preset-radio', true);
82303             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
82304             var enter = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-radio');
82305             enter.append('span').attr('class', 'placeholder');
82306             wrap = wrap.merge(enter);
82307             placeholder = wrap.selectAll('.placeholder');
82308             labels = wrap.selectAll('label').data(radioData);
82309             enter = labels.enter().append('label');
82310             enter.append('input').attr('type', 'radio').attr('name', field.id).attr('value', function (d) {
82311               return field.t('options.' + d, {
82312                 'default': d
82313               });
82314             }).attr('checked', false);
82315             enter.append('span').html(function (d) {
82316               return field.t.html('options.' + d, {
82317                 'default': d
82318               });
82319             });
82320             labels = labels.merge(enter);
82321             radios = labels.selectAll('input').on('change', changeRadio);
82322           }
82323
82324           function structureExtras(selection, tags) {
82325             var selected = selectedKey() || tags.layer !== undefined;
82326             var type = _mainPresetIndex.field(selected);
82327             var layer = _mainPresetIndex.field('layer');
82328             var showLayer = selected === 'bridge' || selected === 'tunnel' || tags.layer !== undefined;
82329             var extrasWrap = selection.selectAll('.structure-extras-wrap').data(selected ? [0] : []);
82330             extrasWrap.exit().remove();
82331             extrasWrap = extrasWrap.enter().append('div').attr('class', 'structure-extras-wrap').merge(extrasWrap);
82332             var list = extrasWrap.selectAll('ul').data([0]);
82333             list = list.enter().append('ul').attr('class', 'rows').merge(list); // Type
82334
82335             if (type) {
82336               if (!typeField || typeField.id !== selected) {
82337                 typeField = uiField(context, type, _entityIDs, {
82338                   wrap: false
82339                 }).on('change', changeType);
82340               }
82341
82342               typeField.tags(tags);
82343             } else {
82344               typeField = null;
82345             }
82346
82347             var typeItem = list.selectAll('.structure-type-item').data(typeField ? [typeField] : [], function (d) {
82348               return d.id;
82349             }); // Exit
82350
82351             typeItem.exit().remove(); // Enter
82352
82353             var typeEnter = typeItem.enter().insert('li', ':first-child').attr('class', 'labeled-input structure-type-item');
82354             typeEnter.append('span').attr('class', 'label structure-label-type').attr('for', 'preset-input-' + selected).html(_t.html('inspector.radio.structure.type'));
82355             typeEnter.append('div').attr('class', 'structure-input-type-wrap'); // Update
82356
82357             typeItem = typeItem.merge(typeEnter);
82358
82359             if (typeField) {
82360               typeItem.selectAll('.structure-input-type-wrap').call(typeField.render);
82361             } // Layer
82362
82363
82364             if (layer && showLayer) {
82365               if (!layerField) {
82366                 layerField = uiField(context, layer, _entityIDs, {
82367                   wrap: false
82368                 }).on('change', changeLayer);
82369               }
82370
82371               layerField.tags(tags);
82372               field.keys = utilArrayUnion(field.keys, ['layer']);
82373             } else {
82374               layerField = null;
82375               field.keys = field.keys.filter(function (k) {
82376                 return k !== 'layer';
82377               });
82378             }
82379
82380             var layerItem = list.selectAll('.structure-layer-item').data(layerField ? [layerField] : []); // Exit
82381
82382             layerItem.exit().remove(); // Enter
82383
82384             var layerEnter = layerItem.enter().append('li').attr('class', 'labeled-input structure-layer-item');
82385             layerEnter.append('span').attr('class', 'label structure-label-layer').attr('for', 'preset-input-layer').html(_t.html('inspector.radio.structure.layer'));
82386             layerEnter.append('div').attr('class', 'structure-input-layer-wrap'); // Update
82387
82388             layerItem = layerItem.merge(layerEnter);
82389
82390             if (layerField) {
82391               layerItem.selectAll('.structure-input-layer-wrap').call(layerField.render);
82392             }
82393           }
82394
82395           function changeType(t, onInput) {
82396             var key = selectedKey();
82397             if (!key) return;
82398             var val = t[key];
82399
82400             if (val !== 'no') {
82401               _oldType[key] = val;
82402             }
82403
82404             if (field.type === 'structureRadio') {
82405               // remove layer if it should not be set
82406               if (val === 'no' || key !== 'bridge' && key !== 'tunnel' || key === 'tunnel' && val === 'building_passage') {
82407                 t.layer = undefined;
82408               } // add layer if it should be set
82409
82410
82411               if (t.layer === undefined) {
82412                 if (key === 'bridge' && val !== 'no') {
82413                   t.layer = '1';
82414                 }
82415
82416                 if (key === 'tunnel' && val !== 'no' && val !== 'building_passage') {
82417                   t.layer = '-1';
82418                 }
82419               }
82420             }
82421
82422             dispatch.call('change', this, t, onInput);
82423           }
82424
82425           function changeLayer(t, onInput) {
82426             if (t.layer === '0') {
82427               t.layer = undefined;
82428             }
82429
82430             dispatch.call('change', this, t, onInput);
82431           }
82432
82433           function changeRadio() {
82434             var t = {};
82435             var activeKey;
82436
82437             if (field.key) {
82438               t[field.key] = undefined;
82439             }
82440
82441             radios.each(function (d) {
82442               var active = select(this).property('checked');
82443               if (active) activeKey = d;
82444
82445               if (field.key) {
82446                 if (active) t[field.key] = d;
82447               } else {
82448                 var val = _oldType[activeKey] || 'yes';
82449                 t[d] = active ? val : undefined;
82450               }
82451             });
82452
82453             if (field.type === 'structureRadio') {
82454               if (activeKey === 'bridge') {
82455                 t.layer = '1';
82456               } else if (activeKey === 'tunnel' && t.tunnel !== 'building_passage') {
82457                 t.layer = '-1';
82458               } else {
82459                 t.layer = undefined;
82460               }
82461             }
82462
82463             dispatch.call('change', this, t);
82464           }
82465
82466           radio.tags = function (tags) {
82467             radios.property('checked', function (d) {
82468               if (field.key) {
82469                 return tags[field.key] === d;
82470               }
82471
82472               return !!(typeof tags[d] === 'string' && tags[d].toLowerCase() !== 'no');
82473             });
82474
82475             function isMixed(d) {
82476               if (field.key) {
82477                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d);
82478               }
82479
82480               return Array.isArray(tags[d]);
82481             }
82482
82483             labels.classed('active', function (d) {
82484               if (field.key) {
82485                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d) || tags[field.key] === d;
82486               }
82487
82488               return Array.isArray(tags[d]) || !!(tags[d] && tags[d].toLowerCase() !== 'no');
82489             }).classed('mixed', isMixed).attr('title', function (d) {
82490               return isMixed(d) ? _t('inspector.unshared_value_tooltip') : null;
82491             });
82492             var selection = radios.filter(function () {
82493               return this.checked;
82494             });
82495
82496             if (selection.empty()) {
82497               placeholder.html(_t.html('inspector.none'));
82498             } else {
82499               placeholder.html(selection.attr('value'));
82500               _oldType[selection.datum()] = tags[selection.datum()];
82501             }
82502
82503             if (field.type === 'structureRadio') {
82504               // For waterways without a tunnel tag, set 'culvert' as
82505               // the _oldType to default to if the user picks 'tunnel'
82506               if (!!tags.waterway && !_oldType.tunnel) {
82507                 _oldType.tunnel = 'culvert';
82508               }
82509
82510               wrap.call(structureExtras, tags);
82511             }
82512           };
82513
82514           radio.focus = function () {
82515             radios.node().focus();
82516           };
82517
82518           radio.entityIDs = function (val) {
82519             if (!arguments.length) return _entityIDs;
82520             _entityIDs = val;
82521             _oldType = {};
82522             return radio;
82523           };
82524
82525           radio.isAllowed = function () {
82526             return _entityIDs.length === 1;
82527           };
82528
82529           return utilRebind(radio, dispatch, 'on');
82530         }
82531
82532         function uiFieldRestrictions(field, context) {
82533           var dispatch = dispatch$8('change');
82534           var breathe = behaviorBreathe();
82535           corePreferences('turn-restriction-via-way', null); // remove old key
82536
82537           var storedViaWay = corePreferences('turn-restriction-via-way0'); // use new key #6922
82538
82539           var storedDistance = corePreferences('turn-restriction-distance');
82540
82541           var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
82542
82543           var _maxDistance = storedDistance ? +storedDistance : 30;
82544
82545           var _initialized = false;
82546
82547           var _parent = select(null); // the entire field
82548
82549
82550           var _container = select(null); // just the map
82551
82552
82553           var _oldTurns;
82554
82555           var _graph;
82556
82557           var _vertexID;
82558
82559           var _intersection;
82560
82561           var _fromWayID;
82562
82563           var _lastXPos;
82564
82565           function restrictions(selection) {
82566             _parent = selection; // try to reuse the intersection, but always rebuild it if the graph has changed
82567
82568             if (_vertexID && (context.graph() !== _graph || !_intersection)) {
82569               _graph = context.graph();
82570               _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
82571             } // It's possible for there to be no actual intersection here.
82572             // for example, a vertex of two `highway=path`
82573             // In this case, hide the field.
82574
82575
82576             var isOK = _intersection && _intersection.vertices.length && // has vertices
82577             _intersection.vertices // has the vertex that the user selected
82578             .filter(function (vertex) {
82579               return vertex.id === _vertexID;
82580             }).length && _intersection.ways.length > 2 && // has more than 2 ways
82581             _intersection.ways // has more than 1 TO way
82582             .filter(function (way) {
82583               return way.__to;
82584             }).length > 1; // Also hide in the case where
82585
82586             select(selection.node().parentNode).classed('hide', !isOK); // if form field is hidden or has detached from dom, clean up.
82587
82588             if (!isOK || !context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode || !selection.node().parentNode.parentNode) {
82589               selection.call(restrictions.off);
82590               return;
82591             }
82592
82593             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
82594             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
82595             var container = wrap.selectAll('.restriction-container').data([0]); // enter
82596
82597             var containerEnter = container.enter().append('div').attr('class', 'restriction-container');
82598             containerEnter.append('div').attr('class', 'restriction-help'); // update
82599
82600             _container = containerEnter.merge(container).call(renderViewer);
82601             var controls = wrap.selectAll('.restriction-controls').data([0]); // enter/update
82602
82603             controls.enter().append('div').attr('class', 'restriction-controls-container').append('div').attr('class', 'restriction-controls').merge(controls).call(renderControls);
82604           }
82605
82606           function renderControls(selection) {
82607             var distControl = selection.selectAll('.restriction-distance').data([0]);
82608             distControl.exit().remove();
82609             var distControlEnter = distControl.enter().append('div').attr('class', 'restriction-control restriction-distance');
82610             distControlEnter.append('span').attr('class', 'restriction-control-label restriction-distance-label').html(_t.html('restriction.controls.distance') + ':');
82611             distControlEnter.append('input').attr('class', 'restriction-distance-input').attr('type', 'range').attr('min', '20').attr('max', '50').attr('step', '5');
82612             distControlEnter.append('span').attr('class', 'restriction-distance-text'); // update
82613
82614             selection.selectAll('.restriction-distance-input').property('value', _maxDistance).on('input', function () {
82615               var val = select(this).property('value');
82616               _maxDistance = +val;
82617               _intersection = null;
82618
82619               _container.selectAll('.layer-osm .layer-turns *').remove();
82620
82621               corePreferences('turn-restriction-distance', _maxDistance);
82622
82623               _parent.call(restrictions);
82624             });
82625             selection.selectAll('.restriction-distance-text').html(displayMaxDistance(_maxDistance));
82626             var viaControl = selection.selectAll('.restriction-via-way').data([0]);
82627             viaControl.exit().remove();
82628             var viaControlEnter = viaControl.enter().append('div').attr('class', 'restriction-control restriction-via-way');
82629             viaControlEnter.append('span').attr('class', 'restriction-control-label restriction-via-way-label').html(_t.html('restriction.controls.via') + ':');
82630             viaControlEnter.append('input').attr('class', 'restriction-via-way-input').attr('type', 'range').attr('min', '0').attr('max', '2').attr('step', '1');
82631             viaControlEnter.append('span').attr('class', 'restriction-via-way-text'); // update
82632
82633             selection.selectAll('.restriction-via-way-input').property('value', _maxViaWay).on('input', function () {
82634               var val = select(this).property('value');
82635               _maxViaWay = +val;
82636
82637               _container.selectAll('.layer-osm .layer-turns *').remove();
82638
82639               corePreferences('turn-restriction-via-way0', _maxViaWay);
82640
82641               _parent.call(restrictions);
82642             });
82643             selection.selectAll('.restriction-via-way-text').html(displayMaxVia(_maxViaWay));
82644           }
82645
82646           function renderViewer(selection) {
82647             if (!_intersection) return;
82648             var vgraph = _intersection.graph;
82649             var filter = utilFunctor(true);
82650             var projection = geoRawMercator(); // Reflow warning: `utilGetDimensions` calls `getBoundingClientRect`
82651             // Instead of asking the restriction-container for its dimensions,
82652             //  we can ask the .sidebar, which can have its dimensions cached.
82653             // width: calc as sidebar - padding
82654             // height: hardcoded (from `80_app.css`)
82655             // var d = utilGetDimensions(selection);
82656
82657             var sdims = utilGetDimensions(context.container().select('.sidebar'));
82658             var d = [sdims[0] - 50, 370];
82659             var c = geoVecScale(d, 0.5);
82660             var z = 22;
82661             projection.scale(geoZoomToScale(z)); // Calculate extent of all key vertices
82662
82663             var extent = geoExtent();
82664
82665             for (var i = 0; i < _intersection.vertices.length; i++) {
82666               extent._extend(_intersection.vertices[i].extent());
82667             } // If this is a large intersection, adjust zoom to fit extent
82668
82669
82670             if (_intersection.vertices.length > 1) {
82671               var padding = 180; // in z22 pixels
82672
82673               var tl = projection([extent[0][0], extent[1][1]]);
82674               var br = projection([extent[1][0], extent[0][1]]);
82675               var hFactor = (br[0] - tl[0]) / (d[0] - padding);
82676               var vFactor = (br[1] - tl[1]) / (d[1] - padding);
82677               var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
82678               var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
82679               z = z - Math.max(hZoomDiff, vZoomDiff);
82680               projection.scale(geoZoomToScale(z));
82681             }
82682
82683             var padTop = 35; // reserve top space for hint text
82684
82685             var extentCenter = projection(extent.center());
82686             extentCenter[1] = extentCenter[1] - padTop;
82687             projection.translate(geoVecSubtract(c, extentCenter)).clipExtent([[0, 0], d]);
82688             var drawLayers = svgLayers(projection, context).only(['osm', 'touch']).dimensions(d);
82689             var drawVertices = svgVertices(projection, context);
82690             var drawLines = svgLines(projection, context);
82691             var drawTurns = svgTurns(projection, context);
82692             var firstTime = selection.selectAll('.surface').empty();
82693             selection.call(drawLayers);
82694             var surface = selection.selectAll('.surface').classed('tr', true);
82695
82696             if (firstTime) {
82697               _initialized = true;
82698               surface.call(breathe);
82699             } // This can happen if we've lowered the detail while a FROM way
82700             // is selected, and that way is no longer part of the intersection.
82701
82702
82703             if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
82704               _fromWayID = null;
82705               _oldTurns = null;
82706             }
82707
82708             surface.call(utilSetDimensions, d).call(drawVertices, vgraph, _intersection.vertices, filter, extent, z).call(drawLines, vgraph, _intersection.ways, filter).call(drawTurns, vgraph, _intersection.turns(_fromWayID, _maxViaWay));
82709             surface.on('click.restrictions', click).on('mouseover.restrictions', mouseover);
82710             surface.selectAll('.selected').classed('selected', false);
82711             surface.selectAll('.related').classed('related', false);
82712             var way;
82713
82714             if (_fromWayID) {
82715               way = vgraph.entity(_fromWayID);
82716               surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
82717             }
82718
82719             document.addEventListener('resizeWindow', function () {
82720               utilSetDimensions(_container, null);
82721               redraw(1);
82722             }, false);
82723             updateHints(null);
82724
82725             function click(d3_event) {
82726               surface.call(breathe.off).call(breathe);
82727               var datum = d3_event.target.__data__;
82728               var entity = datum && datum.properties && datum.properties.entity;
82729
82730               if (entity) {
82731                 datum = entity;
82732               }
82733
82734               if (datum instanceof osmWay && (datum.__from || datum.__via)) {
82735                 _fromWayID = datum.id;
82736                 _oldTurns = null;
82737                 redraw();
82738               } else if (datum instanceof osmTurn) {
82739                 var actions, extraActions, turns, i;
82740                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
82741
82742                 if (datum.restrictionID && !datum.direct) {
82743                   return;
82744                 } else if (datum.restrictionID && !datum.only) {
82745                   // NO -> ONLY
82746                   var seen = {};
82747                   var datumOnly = JSON.parse(JSON.stringify(datum)); // deep clone the datum
82748
82749                   datumOnly.only = true; // but change this property
82750
82751                   restrictionType = restrictionType.replace(/^no/, 'only'); // Adding an ONLY restriction should destroy all other direct restrictions from the FROM towards the VIA.
82752                   // We will remember them in _oldTurns, and restore them if the user clicks again.
82753
82754                   turns = _intersection.turns(_fromWayID, 2);
82755                   extraActions = [];
82756                   _oldTurns = [];
82757
82758                   for (i = 0; i < turns.length; i++) {
82759                     var turn = turns[i];
82760                     if (seen[turn.restrictionID]) continue; // avoid deleting the turn twice (#4968, #4928)
82761
82762                     if (turn.direct && turn.path[1] === datum.path[1]) {
82763                       seen[turns[i].restrictionID] = true;
82764                       turn.restrictionType = osmInferRestriction(vgraph, turn, projection);
82765
82766                       _oldTurns.push(turn);
82767
82768                       extraActions.push(actionUnrestrictTurn(turn));
82769                     }
82770                   }
82771
82772                   actions = _intersection.actions.concat(extraActions, [actionRestrictTurn(datumOnly, restrictionType), _t('operations.restriction.annotation.create')]);
82773                 } else if (datum.restrictionID) {
82774                   // ONLY -> Allowed
82775                   // Restore whatever restrictions we might have destroyed by cycling thru the ONLY state.
82776                   // This relies on the assumption that the intersection was already split up when we
82777                   // performed the previous action (NO -> ONLY), so the IDs in _oldTurns shouldn't have changed.
82778                   turns = _oldTurns || [];
82779                   extraActions = [];
82780
82781                   for (i = 0; i < turns.length; i++) {
82782                     if (turns[i].key !== datum.key) {
82783                       extraActions.push(actionRestrictTurn(turns[i], turns[i].restrictionType));
82784                     }
82785                   }
82786
82787                   _oldTurns = null;
82788                   actions = _intersection.actions.concat(extraActions, [actionUnrestrictTurn(datum), _t('operations.restriction.annotation.delete')]);
82789                 } else {
82790                   // Allowed -> NO
82791                   actions = _intersection.actions.concat([actionRestrictTurn(datum, restrictionType), _t('operations.restriction.annotation.create')]);
82792                 }
82793
82794                 context.perform.apply(context, actions); // At this point the datum will be changed, but will have same key..
82795                 // Refresh it and update the help..
82796
82797                 var s = surface.selectAll('.' + datum.key);
82798                 datum = s.empty() ? null : s.datum();
82799                 updateHints(datum);
82800               } else {
82801                 _fromWayID = null;
82802                 _oldTurns = null;
82803                 redraw();
82804               }
82805             }
82806
82807             function mouseover(d3_event) {
82808               var datum = d3_event.target.__data__;
82809               updateHints(datum);
82810             }
82811
82812             _lastXPos = _lastXPos || sdims[0];
82813
82814             function redraw(minChange) {
82815               var xPos = -1;
82816
82817               if (minChange) {
82818                 xPos = utilGetDimensions(context.container().select('.sidebar'))[0];
82819               }
82820
82821               if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
82822                 if (context.hasEntity(_vertexID)) {
82823                   _lastXPos = xPos;
82824
82825                   _container.call(renderViewer);
82826                 }
82827               }
82828             }
82829
82830             function highlightPathsFrom(wayID) {
82831               surface.selectAll('.related').classed('related', false).classed('allow', false).classed('restrict', false).classed('only', false);
82832               surface.selectAll('.' + wayID).classed('related', true);
82833
82834               if (wayID) {
82835                 var turns = _intersection.turns(wayID, _maxViaWay);
82836
82837                 for (var i = 0; i < turns.length; i++) {
82838                   var turn = turns[i];
82839                   var ids = [turn.to.way];
82840                   var klass = turn.no ? 'restrict' : turn.only ? 'only' : 'allow';
82841
82842                   if (turn.only || turns.length === 1) {
82843                     if (turn.via.ways) {
82844                       ids = ids.concat(turn.via.ways);
82845                     }
82846                   } else if (turn.to.way === wayID) {
82847                     continue;
82848                   }
82849
82850                   surface.selectAll(utilEntitySelector(ids)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only');
82851                 }
82852               }
82853             }
82854
82855             function updateHints(datum) {
82856               var help = _container.selectAll('.restriction-help').html('');
82857
82858               var placeholders = {};
82859               ['from', 'via', 'to'].forEach(function (k) {
82860                 placeholders[k] = '<span class="qualifier">' + _t('restriction.help.' + k) + '</span>';
82861               });
82862               var entity = datum && datum.properties && datum.properties.entity;
82863
82864               if (entity) {
82865                 datum = entity;
82866               }
82867
82868               if (_fromWayID) {
82869                 way = vgraph.entity(_fromWayID);
82870                 surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
82871               } // Hovering a way
82872
82873
82874               if (datum instanceof osmWay && datum.__from) {
82875                 way = datum;
82876                 highlightPathsFrom(_fromWayID ? null : way.id);
82877                 surface.selectAll('.' + way.id).classed('related', true);
82878                 var clickSelect = !_fromWayID || _fromWayID !== way.id;
82879                 help.append('div') // "Click to select FROM {fromName}." / "FROM {fromName}"
82880                 .html(_t.html('restriction.help.' + (clickSelect ? 'select_from_name' : 'from_name'), {
82881                   from: placeholders.from,
82882                   fromName: displayName(way.id, vgraph)
82883                 })); // Hovering a turn arrow
82884               } else if (datum instanceof osmTurn) {
82885                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
82886                 var turnType = restrictionType.replace(/^(only|no)\_/, '');
82887                 var indirect = datum.direct === false ? _t.html('restriction.help.indirect') : '';
82888                 var klass, turnText, nextText;
82889
82890                 if (datum.no) {
82891                   klass = 'restrict';
82892                   turnText = _t.html('restriction.help.turn.no_' + turnType, {
82893                     indirect: indirect
82894                   });
82895                   nextText = _t.html('restriction.help.turn.only_' + turnType, {
82896                     indirect: ''
82897                   });
82898                 } else if (datum.only) {
82899                   klass = 'only';
82900                   turnText = _t.html('restriction.help.turn.only_' + turnType, {
82901                     indirect: indirect
82902                   });
82903                   nextText = _t.html('restriction.help.turn.allowed_' + turnType, {
82904                     indirect: ''
82905                   });
82906                 } else {
82907                   klass = 'allow';
82908                   turnText = _t.html('restriction.help.turn.allowed_' + turnType, {
82909                     indirect: indirect
82910                   });
82911                   nextText = _t.html('restriction.help.turn.no_' + turnType, {
82912                     indirect: ''
82913                   });
82914                 }
82915
82916                 help.append('div') // "NO Right Turn (indirect)"
82917                 .attr('class', 'qualifier ' + klass).html(turnText);
82918                 help.append('div') // "FROM {fromName} TO {toName}"
82919                 .html(_t.html('restriction.help.from_name_to_name', {
82920                   from: placeholders.from,
82921                   fromName: displayName(datum.from.way, vgraph),
82922                   to: placeholders.to,
82923                   toName: displayName(datum.to.way, vgraph)
82924                 }));
82925
82926                 if (datum.via.ways && datum.via.ways.length) {
82927                   var names = [];
82928
82929                   for (var i = 0; i < datum.via.ways.length; i++) {
82930                     var prev = names[names.length - 1];
82931                     var curr = displayName(datum.via.ways[i], vgraph);
82932
82933                     if (!prev || curr !== prev) {
82934                       // collapse identical names
82935                       names.push(curr);
82936                     }
82937                   }
82938
82939                   help.append('div') // "VIA {viaNames}"
82940                   .html(_t.html('restriction.help.via_names', {
82941                     via: placeholders.via,
82942                     viaNames: names.join(', ')
82943                   }));
82944                 }
82945
82946                 if (!indirect) {
82947                   help.append('div') // Click for "No Right Turn"
82948                   .html(_t.html('restriction.help.toggle', {
82949                     turn: nextText.trim()
82950                   }));
82951                 }
82952
82953                 highlightPathsFrom(null);
82954                 var alongIDs = datum.path.slice();
82955                 surface.selectAll(utilEntitySelector(alongIDs)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only'); // Hovering empty surface
82956               } else {
82957                 highlightPathsFrom(null);
82958
82959                 if (_fromWayID) {
82960                   help.append('div') // "FROM {fromName}"
82961                   .html(_t.html('restriction.help.from_name', {
82962                     from: placeholders.from,
82963                     fromName: displayName(_fromWayID, vgraph)
82964                   }));
82965                 } else {
82966                   help.append('div') // "Click to select a FROM segment."
82967                   .html(_t.html('restriction.help.select_from', {
82968                     from: placeholders.from
82969                   }));
82970                 }
82971               }
82972             }
82973           }
82974
82975           function displayMaxDistance(maxDist) {
82976             var isImperial = !_mainLocalizer.usesMetric();
82977             var opts;
82978
82979             if (isImperial) {
82980               var distToFeet = {
82981                 // imprecise conversion for prettier display
82982                 20: 70,
82983                 25: 85,
82984                 30: 100,
82985                 35: 115,
82986                 40: 130,
82987                 45: 145,
82988                 50: 160
82989               }[maxDist];
82990               opts = {
82991                 distance: _t('units.feet', {
82992                   quantity: distToFeet
82993                 })
82994               };
82995             } else {
82996               opts = {
82997                 distance: _t('units.meters', {
82998                   quantity: maxDist
82999                 })
83000               };
83001             }
83002
83003             return _t.html('restriction.controls.distance_up_to', opts);
83004           }
83005
83006           function displayMaxVia(maxVia) {
83007             return maxVia === 0 ? _t.html('restriction.controls.via_node_only') : maxVia === 1 ? _t.html('restriction.controls.via_up_to_one') : _t.html('restriction.controls.via_up_to_two');
83008           }
83009
83010           function displayName(entityID, graph) {
83011             var entity = graph.entity(entityID);
83012             var name = utilDisplayName(entity) || '';
83013             var matched = _mainPresetIndex.match(entity, graph);
83014             var type = matched && matched.name() || utilDisplayType(entity.id);
83015             return name || type;
83016           }
83017
83018           restrictions.entityIDs = function (val) {
83019             _intersection = null;
83020             _fromWayID = null;
83021             _oldTurns = null;
83022             _vertexID = val[0];
83023           };
83024
83025           restrictions.tags = function () {};
83026
83027           restrictions.focus = function () {};
83028
83029           restrictions.off = function (selection) {
83030             if (!_initialized) return;
83031             selection.selectAll('.surface').call(breathe.off).on('click.restrictions', null).on('mouseover.restrictions', null);
83032             select(window).on('resize.restrictions', null);
83033           };
83034
83035           return utilRebind(restrictions, dispatch, 'on');
83036         }
83037         uiFieldRestrictions.supportsMultiselection = false;
83038
83039         function uiFieldTextarea(field, context) {
83040           var dispatch = dispatch$8('change');
83041           var input = select(null);
83042
83043           var _tags;
83044
83045           function textarea(selection) {
83046             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
83047             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
83048             input = wrap.selectAll('textarea').data([0]);
83049             input = input.enter().append('textarea').attr('id', field.domId).call(utilNoAuto).on('input', change(true)).on('blur', change()).on('change', change()).merge(input);
83050           }
83051
83052           function change(onInput) {
83053             return function () {
83054               var val = utilGetSetValue(input);
83055               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
83056
83057               if (!val && Array.isArray(_tags[field.key])) return;
83058               var t = {};
83059               t[field.key] = val || undefined;
83060               dispatch.call('change', this, t, onInput);
83061             };
83062           }
83063
83064           textarea.tags = function (tags) {
83065             _tags = tags;
83066             var isMixed = Array.isArray(tags[field.key]);
83067             utilGetSetValue(input, !isMixed && tags[field.key] ? tags[field.key] : '').attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : undefined).attr('placeholder', isMixed ? _t('inspector.multiple_values') : field.placeholder() || _t('inspector.unknown')).classed('mixed', isMixed);
83068           };
83069
83070           textarea.focus = function () {
83071             input.node().focus();
83072           };
83073
83074           return utilRebind(textarea, dispatch, 'on');
83075         }
83076
83077         var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
83078
83079
83080
83081
83082
83083
83084         // eslint-disable-next-line es/no-string-prototype-endswith -- safe
83085         var $endsWith = ''.endsWith;
83086         var min = Math.min;
83087
83088         var CORRECT_IS_REGEXP_LOGIC = correctIsRegexpLogic('endsWith');
83089         // https://github.com/zloirock/core-js/pull/702
83090         var MDN_POLYFILL_BUG = !CORRECT_IS_REGEXP_LOGIC && !!function () {
83091           var descriptor = getOwnPropertyDescriptor(String.prototype, 'endsWith');
83092           return descriptor && !descriptor.writable;
83093         }();
83094
83095         // `String.prototype.endsWith` method
83096         // https://tc39.es/ecma262/#sec-string.prototype.endswith
83097         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG && !CORRECT_IS_REGEXP_LOGIC }, {
83098           endsWith: function endsWith(searchString /* , endPosition = @length */) {
83099             var that = String(requireObjectCoercible(this));
83100             notARegexp(searchString);
83101             var endPosition = arguments.length > 1 ? arguments[1] : undefined;
83102             var len = toLength(that.length);
83103             var end = endPosition === undefined ? len : min(toLength(endPosition), len);
83104             var search = String(searchString);
83105             return $endsWith
83106               ? $endsWith.call(that, search, end)
83107               : that.slice(end - search.length, end) === search;
83108           }
83109         });
83110
83111         function uiFieldWikidata(field, context) {
83112           var wikidata = services.wikidata;
83113           var dispatch = dispatch$8('change');
83114
83115           var _selection = select(null);
83116
83117           var _searchInput = select(null);
83118
83119           var _qid = null;
83120           var _wikidataEntity = null;
83121           var _wikiURL = '';
83122           var _entityIDs = [];
83123
83124           var _wikipediaKey = field.keys && field.keys.find(function (key) {
83125             return key.includes('wikipedia');
83126           }),
83127               _hintKey = field.key === 'wikidata' ? 'name' : field.key.split(':')[0];
83128
83129           var combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(true).minItems(1);
83130
83131           function wiki(selection) {
83132             _selection = selection;
83133             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
83134             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
83135             var list = wrap.selectAll('ul').data([0]);
83136             list = list.enter().append('ul').attr('class', 'rows').merge(list);
83137             var searchRow = list.selectAll('li.wikidata-search').data([0]);
83138             var searchRowEnter = searchRow.enter().append('li').attr('class', 'wikidata-search');
83139             searchRowEnter.append('input').attr('type', 'text').attr('id', field.domId).style('flex', '1').call(utilNoAuto).on('focus', function () {
83140               var node = select(this).node();
83141               node.setSelectionRange(0, node.value.length);
83142             }).on('blur', function () {
83143               setLabelForEntity();
83144             }).call(combobox.fetcher(fetchWikidataItems));
83145             combobox.on('accept', function (d) {
83146               if (d) {
83147                 _qid = d.id;
83148                 change();
83149               }
83150             }).on('cancel', function () {
83151               setLabelForEntity();
83152             });
83153             searchRowEnter.append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
83154               domain: 'wikidata.org'
83155             })).call(svgIcon('#iD-icon-out-link')).on('click', function (d3_event) {
83156               d3_event.preventDefault();
83157               if (_wikiURL) window.open(_wikiURL, '_blank');
83158             });
83159             searchRow = searchRow.merge(searchRowEnter);
83160             _searchInput = searchRow.select('input');
83161             var wikidataProperties = ['description', 'identifier'];
83162             var items = list.selectAll('li.labeled-input').data(wikidataProperties); // Enter
83163
83164             var enter = items.enter().append('li').attr('class', function (d) {
83165               return 'labeled-input preset-wikidata-' + d;
83166             });
83167             enter.append('span').attr('class', 'label').html(function (d) {
83168               return _t.html('wikidata.' + d);
83169             });
83170             enter.append('input').attr('type', 'text').call(utilNoAuto).classed('disabled', 'true').attr('readonly', 'true');
83171             enter.append('button').attr('class', 'form-field-button').attr('title', _t('icons.copy')).call(svgIcon('#iD-operation-copy')).on('click', function (d3_event) {
83172               d3_event.preventDefault();
83173               select(this.parentNode).select('input').node().select();
83174               document.execCommand('copy');
83175             });
83176           }
83177
83178           function fetchWikidataItems(q, callback) {
83179             if (!q && _hintKey) {
83180               // other tags may be good search terms
83181               for (var i in _entityIDs) {
83182                 var entity = context.hasEntity(_entityIDs[i]);
83183
83184                 if (entity.tags[_hintKey]) {
83185                   q = entity.tags[_hintKey];
83186                   break;
83187                 }
83188               }
83189             }
83190
83191             wikidata.itemsForSearchQuery(q, function (err, data) {
83192               if (err) return;
83193
83194               for (var i in data) {
83195                 data[i].value = data[i].label + ' (' + data[i].id + ')';
83196                 data[i].title = data[i].description;
83197               }
83198
83199               if (callback) callback(data);
83200             });
83201           }
83202
83203           function change() {
83204             var syncTags = {};
83205             syncTags[field.key] = _qid;
83206             dispatch.call('change', this, syncTags); // attempt asynchronous update of wikidata tag..
83207
83208             var initGraph = context.graph();
83209             var initEntityIDs = _entityIDs;
83210             wikidata.entityByQID(_qid, function (err, entity) {
83211               if (err) return; // If graph has changed, we can't apply this update.
83212
83213               if (context.graph() !== initGraph) return;
83214               if (!entity.sitelinks) return;
83215               var langs = wikidata.languagesToQuery(); // use the label and description languages as fallbacks
83216
83217               ['labels', 'descriptions'].forEach(function (key) {
83218                 if (!entity[key]) return;
83219                 var valueLangs = Object.keys(entity[key]);
83220                 if (valueLangs.length === 0) return;
83221                 var valueLang = valueLangs[0];
83222
83223                 if (langs.indexOf(valueLang) === -1) {
83224                   langs.push(valueLang);
83225                 }
83226               });
83227               var newWikipediaValue;
83228
83229               if (_wikipediaKey) {
83230                 var foundPreferred;
83231
83232                 for (var i in langs) {
83233                   var lang = langs[i];
83234                   var siteID = lang.replace('-', '_') + 'wiki';
83235
83236                   if (entity.sitelinks[siteID]) {
83237                     foundPreferred = true;
83238                     newWikipediaValue = lang + ':' + entity.sitelinks[siteID].title; // use the first match
83239
83240                     break;
83241                   }
83242                 }
83243
83244                 if (!foundPreferred) {
83245                   // No wikipedia sites available in the user's language or the fallback languages,
83246                   // default to any wikipedia sitelink
83247                   var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function (site) {
83248                     return site.endsWith('wiki');
83249                   });
83250
83251                   if (wikiSiteKeys.length === 0) {
83252                     // if no wikipedia pages are linked to this wikidata entity, delete that tag
83253                     newWikipediaValue = null;
83254                   } else {
83255                     var wikiLang = wikiSiteKeys[0].slice(0, -4).replace('_', '-');
83256                     var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
83257                     newWikipediaValue = wikiLang + ':' + wikiTitle;
83258                   }
83259                 }
83260               }
83261
83262               if (newWikipediaValue) {
83263                 newWikipediaValue = context.cleanTagValue(newWikipediaValue);
83264               }
83265
83266               if (typeof newWikipediaValue === 'undefined') return;
83267               var actions = initEntityIDs.map(function (entityID) {
83268                 var entity = context.hasEntity(entityID);
83269                 if (!entity) return null;
83270                 var currTags = Object.assign({}, entity.tags); // shallow copy
83271
83272                 if (newWikipediaValue === null) {
83273                   if (!currTags[_wikipediaKey]) return null;
83274                   delete currTags[_wikipediaKey];
83275                 } else {
83276                   currTags[_wikipediaKey] = newWikipediaValue;
83277                 }
83278
83279                 return actionChangeTags(entityID, currTags);
83280               }).filter(Boolean);
83281               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
83282
83283               context.overwrite(function actionUpdateWikipediaTags(graph) {
83284                 actions.forEach(function (action) {
83285                   graph = action(graph);
83286                 });
83287                 return graph;
83288               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
83289               // changeTags() is not intended to be called asynchronously
83290             });
83291           }
83292
83293           function setLabelForEntity() {
83294             var label = '';
83295
83296             if (_wikidataEntity) {
83297               label = entityPropertyForDisplay(_wikidataEntity, 'labels');
83298
83299               if (label.length === 0) {
83300                 label = _wikidataEntity.id.toString();
83301               }
83302             }
83303
83304             utilGetSetValue(_searchInput, label);
83305           }
83306
83307           wiki.tags = function (tags) {
83308             var isMixed = Array.isArray(tags[field.key]);
83309
83310             _searchInput.attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : '').classed('mixed', isMixed);
83311
83312             _qid = typeof tags[field.key] === 'string' && tags[field.key] || '';
83313
83314             if (!/^Q[0-9]*$/.test(_qid)) {
83315               // not a proper QID
83316               unrecognized();
83317               return;
83318             } // QID value in correct format
83319
83320
83321             _wikiURL = 'https://wikidata.org/wiki/' + _qid;
83322             wikidata.entityByQID(_qid, function (err, entity) {
83323               if (err) {
83324                 unrecognized();
83325                 return;
83326               }
83327
83328               _wikidataEntity = entity;
83329               setLabelForEntity();
83330               var description = entityPropertyForDisplay(entity, 'descriptions');
83331
83332               _selection.select('button.wiki-link').classed('disabled', false);
83333
83334               _selection.select('.preset-wikidata-description').style('display', function () {
83335                 return description.length > 0 ? 'flex' : 'none';
83336               }).select('input').attr('value', description);
83337
83338               _selection.select('.preset-wikidata-identifier').style('display', function () {
83339                 return entity.id ? 'flex' : 'none';
83340               }).select('input').attr('value', entity.id);
83341             }); // not a proper QID
83342
83343             function unrecognized() {
83344               _wikidataEntity = null;
83345               setLabelForEntity();
83346
83347               _selection.select('.preset-wikidata-description').style('display', 'none');
83348
83349               _selection.select('.preset-wikidata-identifier').style('display', 'none');
83350
83351               _selection.select('button.wiki-link').classed('disabled', true);
83352
83353               if (_qid && _qid !== '') {
83354                 _wikiURL = 'https://wikidata.org/wiki/Special:Search?search=' + _qid;
83355               } else {
83356                 _wikiURL = '';
83357               }
83358             }
83359           };
83360
83361           function entityPropertyForDisplay(wikidataEntity, propKey) {
83362             if (!wikidataEntity[propKey]) return '';
83363             var propObj = wikidataEntity[propKey];
83364             var langKeys = Object.keys(propObj);
83365             if (langKeys.length === 0) return ''; // sorted by priority, since we want to show the user's language first if possible
83366
83367             var langs = wikidata.languagesToQuery();
83368
83369             for (var i in langs) {
83370               var lang = langs[i];
83371               var valueObj = propObj[lang];
83372               if (valueObj && valueObj.value && valueObj.value.length > 0) return valueObj.value;
83373             } // default to any available value
83374
83375
83376             return propObj[langKeys[0]].value;
83377           }
83378
83379           wiki.entityIDs = function (val) {
83380             if (!arguments.length) return _entityIDs;
83381             _entityIDs = val;
83382             return wiki;
83383           };
83384
83385           wiki.focus = function () {
83386             _searchInput.node().focus();
83387           };
83388
83389           return utilRebind(wiki, dispatch, 'on');
83390         }
83391
83392         function uiFieldWikipedia(field, context) {
83393           var _arguments = arguments;
83394           var dispatch = dispatch$8('change');
83395           var wikipedia = services.wikipedia;
83396           var wikidata = services.wikidata;
83397
83398           var _langInput = select(null);
83399
83400           var _titleInput = select(null);
83401
83402           var _wikiURL = '';
83403
83404           var _entityIDs;
83405
83406           var _tags;
83407
83408           var _dataWikipedia = [];
83409           _mainFileFetcher.get('wmf_sitematrix').then(function (d) {
83410             _dataWikipedia = d;
83411             if (_tags) updateForTags(_tags);
83412           })["catch"](function () {
83413             /* ignore */
83414           });
83415           var langCombo = uiCombobox(context, 'wikipedia-lang').fetcher(function (value, callback) {
83416             var v = value.toLowerCase();
83417             callback(_dataWikipedia.filter(function (d) {
83418               return d[0].toLowerCase().indexOf(v) >= 0 || d[1].toLowerCase().indexOf(v) >= 0 || d[2].toLowerCase().indexOf(v) >= 0;
83419             }).map(function (d) {
83420               return {
83421                 value: d[1]
83422               };
83423             }));
83424           });
83425           var titleCombo = uiCombobox(context, 'wikipedia-title').fetcher(function (value, callback) {
83426             if (!value) {
83427               value = '';
83428
83429               for (var i in _entityIDs) {
83430                 var entity = context.hasEntity(_entityIDs[i]);
83431
83432                 if (entity.tags.name) {
83433                   value = entity.tags.name;
83434                   break;
83435                 }
83436               }
83437             }
83438
83439             var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
83440             searchfn(language()[2], value, function (query, data) {
83441               callback(data.map(function (d) {
83442                 return {
83443                   value: d
83444                 };
83445               }));
83446             });
83447           });
83448
83449           function wiki(selection) {
83450             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
83451             wrap = wrap.enter().append('div').attr('class', "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap);
83452             var langContainer = wrap.selectAll('.wiki-lang-container').data([0]);
83453             langContainer = langContainer.enter().append('div').attr('class', 'wiki-lang-container').merge(langContainer);
83454             _langInput = langContainer.selectAll('input.wiki-lang').data([0]);
83455             _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);
83456
83457             _langInput.on('blur', changeLang).on('change', changeLang);
83458
83459             var titleContainer = wrap.selectAll('.wiki-title-container').data([0]);
83460             titleContainer = titleContainer.enter().append('div').attr('class', 'wiki-title-container').merge(titleContainer);
83461             _titleInput = titleContainer.selectAll('input.wiki-title').data([0]);
83462             _titleInput = _titleInput.enter().append('input').attr('type', 'text').attr('class', 'wiki-title').attr('id', field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
83463
83464             _titleInput.on('blur', function () {
83465               change(true);
83466             }).on('change', function () {
83467               change(false);
83468             });
83469
83470             var link = titleContainer.selectAll('.wiki-link').data([0]);
83471             link = link.enter().append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
83472               domain: 'wikipedia.org'
83473             })).call(svgIcon('#iD-icon-out-link')).merge(link);
83474             link.on('click', function (d3_event) {
83475               d3_event.preventDefault();
83476               if (_wikiURL) window.open(_wikiURL, '_blank');
83477             });
83478           }
83479
83480           function defaultLanguageInfo(skipEnglishFallback) {
83481             var langCode = _mainLocalizer.languageCode().toLowerCase();
83482
83483             for (var i in _dataWikipedia) {
83484               var d = _dataWikipedia[i]; // default to the language of iD's current locale
83485
83486               if (d[2] === langCode) return d;
83487             } // fallback to English
83488
83489
83490             return skipEnglishFallback ? ['', '', ''] : ['English', 'English', 'en'];
83491           }
83492
83493           function language(skipEnglishFallback) {
83494             var value = utilGetSetValue(_langInput).toLowerCase();
83495
83496             for (var i in _dataWikipedia) {
83497               var d = _dataWikipedia[i]; // return the language already set in the UI, if supported
83498
83499               if (d[0].toLowerCase() === value || d[1].toLowerCase() === value || d[2] === value) return d;
83500             } // fallback to English
83501
83502
83503             return defaultLanguageInfo(skipEnglishFallback);
83504           }
83505
83506           function changeLang() {
83507             utilGetSetValue(_langInput, language()[1]);
83508             change(true);
83509           }
83510
83511           function change(skipWikidata) {
83512             var value = utilGetSetValue(_titleInput);
83513             var m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
83514
83515             var langInfo = m && _dataWikipedia.find(function (d) {
83516               return m[1] === d[2];
83517             });
83518
83519             var syncTags = {};
83520
83521             if (langInfo) {
83522               var nativeLangName = langInfo[1]; // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
83523
83524               value = decodeURIComponent(m[2]).replace(/_/g, ' ');
83525
83526               if (m[3]) {
83527                 var anchor; // try {
83528                 // leave this out for now - #6232
83529                 // Best-effort `anchordecode:` implementation
83530                 // anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
83531                 // } catch (e) {
83532
83533                 anchor = decodeURIComponent(m[3]); // }
83534
83535                 value += '#' + anchor.replace(/_/g, ' ');
83536               }
83537
83538               value = value.slice(0, 1).toUpperCase() + value.slice(1);
83539               utilGetSetValue(_langInput, nativeLangName);
83540               utilGetSetValue(_titleInput, value);
83541             }
83542
83543             if (value) {
83544               syncTags.wikipedia = context.cleanTagValue(language()[2] + ':' + value);
83545             } else {
83546               syncTags.wikipedia = undefined;
83547             }
83548
83549             dispatch.call('change', this, syncTags);
83550             if (skipWikidata || !value || !language()[2]) return; // attempt asynchronous update of wikidata tag..
83551
83552             var initGraph = context.graph();
83553             var initEntityIDs = _entityIDs;
83554             wikidata.itemsByTitle(language()[2], value, function (err, data) {
83555               if (err || !data || !Object.keys(data).length) return; // If graph has changed, we can't apply this update.
83556
83557               if (context.graph() !== initGraph) return;
83558               var qids = Object.keys(data);
83559               var value = qids && qids.find(function (id) {
83560                 return id.match(/^Q\d+$/);
83561               });
83562               var actions = initEntityIDs.map(function (entityID) {
83563                 var entity = context.entity(entityID).tags;
83564                 var currTags = Object.assign({}, entity); // shallow copy
83565
83566                 if (currTags.wikidata !== value) {
83567                   currTags.wikidata = value;
83568                   return actionChangeTags(entityID, currTags);
83569                 }
83570
83571                 return null;
83572               }).filter(Boolean);
83573               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
83574
83575               context.overwrite(function actionUpdateWikidataTags(graph) {
83576                 actions.forEach(function (action) {
83577                   graph = action(graph);
83578                 });
83579                 return graph;
83580               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
83581               // changeTags() is not intended to be called asynchronously
83582             });
83583           }
83584
83585           wiki.tags = function (tags) {
83586             _tags = tags;
83587             updateForTags(tags);
83588           };
83589
83590           function updateForTags(tags) {
83591             var value = typeof tags[field.key] === 'string' ? tags[field.key] : ''; // Expect tag format of `tagLang:tagArticleTitle`, e.g. `fr:Paris`, with
83592             // optional suffix of `#anchor`
83593
83594             var m = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
83595             var tagLang = m && m[1];
83596             var tagArticleTitle = m && m[2];
83597             var anchor = m && m[3];
83598
83599             var tagLangInfo = tagLang && _dataWikipedia.find(function (d) {
83600               return tagLang === d[2];
83601             }); // value in correct format
83602
83603
83604             if (tagLangInfo) {
83605               var nativeLangName = tagLangInfo[1];
83606               utilGetSetValue(_langInput, nativeLangName);
83607               utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? '#' + anchor : ''));
83608
83609               if (anchor) {
83610                 try {
83611                   // Best-effort `anchorencode:` implementation
83612                   anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
83613                 } catch (e) {
83614                   anchor = anchor.replace(/ /g, '_');
83615                 }
83616               }
83617
83618               _wikiURL = 'https://' + tagLang + '.wikipedia.org/wiki/' + tagArticleTitle.replace(/ /g, '_') + (anchor ? '#' + anchor : ''); // unrecognized value format
83619             } else {
83620               utilGetSetValue(_titleInput, value);
83621
83622               if (value && value !== '') {
83623                 utilGetSetValue(_langInput, '');
83624                 var defaultLangInfo = defaultLanguageInfo();
83625                 _wikiURL = "https://".concat(defaultLangInfo[2], ".wikipedia.org/w/index.php?fulltext=1&search=").concat(value);
83626               } else {
83627                 var shownOrDefaultLangInfo = language(true
83628                 /* skipEnglishFallback */
83629                 );
83630                 utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
83631                 _wikiURL = '';
83632               }
83633             }
83634           }
83635
83636           wiki.entityIDs = function (val) {
83637             if (!_arguments.length) return _entityIDs;
83638             _entityIDs = val;
83639             return wiki;
83640           };
83641
83642           wiki.focus = function () {
83643             _titleInput.node().focus();
83644           };
83645
83646           return utilRebind(wiki, dispatch, 'on');
83647         }
83648         uiFieldWikipedia.supportsMultiselection = false;
83649
83650         var uiFields = {
83651           access: uiFieldAccess,
83652           address: uiFieldAddress,
83653           check: uiFieldCheck,
83654           combo: uiFieldCombo,
83655           cycleway: uiFieldCycleway,
83656           defaultCheck: uiFieldCheck,
83657           email: uiFieldText,
83658           identifier: uiFieldText,
83659           lanes: uiFieldLanes,
83660           localized: uiFieldLocalized,
83661           roadspeed: uiFieldRoadspeed,
83662           roadheight: uiFieldText,
83663           manyCombo: uiFieldCombo,
83664           multiCombo: uiFieldCombo,
83665           networkCombo: uiFieldCombo,
83666           number: uiFieldText,
83667           onewayCheck: uiFieldCheck,
83668           radio: uiFieldRadio,
83669           restrictions: uiFieldRestrictions,
83670           semiCombo: uiFieldCombo,
83671           structureRadio: uiFieldRadio,
83672           tel: uiFieldText,
83673           text: uiFieldText,
83674           textarea: uiFieldTextarea,
83675           typeCombo: uiFieldCombo,
83676           url: uiFieldText,
83677           wikidata: uiFieldWikidata,
83678           wikipedia: uiFieldWikipedia
83679         };
83680
83681         function uiField(context, presetField, entityIDs, options) {
83682           options = Object.assign({
83683             show: true,
83684             wrap: true,
83685             remove: true,
83686             revert: true,
83687             info: true
83688           }, options);
83689           var dispatch = dispatch$8('change', 'revert');
83690           var field = Object.assign({}, presetField); // shallow copy
83691
83692           field.domId = utilUniqueDomId('form-field-' + field.safeid);
83693           var _show = options.show;
83694           var _state = '';
83695           var _tags = {};
83696
83697           var _entityExtent;
83698
83699           if (entityIDs && entityIDs.length) {
83700             _entityExtent = entityIDs.reduce(function (extent, entityID) {
83701               var entity = context.graph().entity(entityID);
83702               return extent.extend(entity.extent(context.graph()));
83703             }, geoExtent());
83704           }
83705
83706           var _locked = false;
83707
83708           var _lockedTip = uiTooltip().title(_t.html('inspector.lock.suggestion', {
83709             label: field.label
83710           })).placement('bottom');
83711
83712           field.keys = field.keys || [field.key]; // only create the fields that are actually being shown
83713
83714           if (_show && !field.impl) {
83715             createField();
83716           } // Creates the field.. This is done lazily,
83717           // once we know that the field will be shown.
83718
83719
83720           function createField() {
83721             field.impl = uiFields[field.type](field, context).on('change', function (t, onInput) {
83722               dispatch.call('change', field, t, onInput);
83723             });
83724
83725             if (entityIDs) {
83726               field.entityIDs = entityIDs; // if this field cares about the entities, pass them along
83727
83728               if (field.impl.entityIDs) {
83729                 field.impl.entityIDs(entityIDs);
83730               }
83731             }
83732           }
83733
83734           function isModified() {
83735             if (!entityIDs || !entityIDs.length) return false;
83736             return entityIDs.some(function (entityID) {
83737               var original = context.graph().base().entities[entityID];
83738               var latest = context.graph().entity(entityID);
83739               return field.keys.some(function (key) {
83740                 return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
83741               });
83742             });
83743           }
83744
83745           function tagsContainFieldKey() {
83746             return field.keys.some(function (key) {
83747               if (field.type === 'multiCombo') {
83748                 for (var tagKey in _tags) {
83749                   if (tagKey.indexOf(key) === 0) {
83750                     return true;
83751                   }
83752                 }
83753
83754                 return false;
83755               }
83756
83757               return _tags[key] !== undefined;
83758             });
83759           }
83760
83761           function revert(d3_event, d) {
83762             d3_event.stopPropagation();
83763             d3_event.preventDefault();
83764             if (!entityIDs || _locked) return;
83765             dispatch.call('revert', d, d.keys);
83766           }
83767
83768           function remove(d3_event, d) {
83769             d3_event.stopPropagation();
83770             d3_event.preventDefault();
83771             if (_locked) return;
83772             var t = {};
83773             d.keys.forEach(function (key) {
83774               t[key] = undefined;
83775             });
83776             dispatch.call('change', d, t);
83777           }
83778
83779           field.render = function (selection) {
83780             var container = selection.selectAll('.form-field').data([field]); // Enter
83781
83782             var enter = container.enter().append('div').attr('class', function (d) {
83783               return 'form-field form-field-' + d.safeid;
83784             }).classed('nowrap', !options.wrap);
83785
83786             if (options.wrap) {
83787               var labelEnter = enter.append('label').attr('class', 'field-label').attr('for', function (d) {
83788                 return d.domId;
83789               });
83790               var textEnter = labelEnter.append('span').attr('class', 'label-text');
83791               textEnter.append('span').attr('class', 'label-textvalue').html(function (d) {
83792                 return d.label();
83793               });
83794               textEnter.append('span').attr('class', 'label-textannotation');
83795
83796               if (options.remove) {
83797                 labelEnter.append('button').attr('class', 'remove-icon').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete'));
83798               }
83799
83800               if (options.revert) {
83801                 labelEnter.append('button').attr('class', 'modified-icon').attr('title', _t('icons.undo')).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo'));
83802               }
83803             } // Update
83804
83805
83806             container = container.merge(enter);
83807             container.select('.field-label > .remove-icon') // propagate bound data
83808             .on('click', remove);
83809             container.select('.field-label > .modified-icon') // propagate bound data
83810             .on('click', revert);
83811             container.each(function (d) {
83812               var selection = select(this);
83813
83814               if (!d.impl) {
83815                 createField();
83816               }
83817
83818               var reference, help; // instantiate field help
83819
83820               if (options.wrap && field.type === 'restrictions') {
83821                 help = uiFieldHelp(context, 'restrictions');
83822               } // instantiate tag reference
83823
83824
83825               if (options.wrap && options.info) {
83826                 var referenceKey = d.key || '';
83827
83828                 if (d.type === 'multiCombo') {
83829                   // lookup key without the trailing ':'
83830                   referenceKey = referenceKey.replace(/:$/, '');
83831                 }
83832
83833                 reference = uiTagReference(d.reference || {
83834                   key: referenceKey
83835                 });
83836
83837                 if (_state === 'hover') {
83838                   reference.showing(false);
83839                 }
83840               }
83841
83842               selection.call(d.impl); // add field help components
83843
83844               if (help) {
83845                 selection.call(help.body).select('.field-label').call(help.button);
83846               } // add tag reference components
83847
83848
83849               if (reference) {
83850                 selection.call(reference.body).select('.field-label').call(reference.button);
83851               }
83852
83853               d.impl.tags(_tags);
83854             });
83855             container.classed('locked', _locked).classed('modified', isModified()).classed('present', tagsContainFieldKey()); // show a tip and lock icon if the field is locked
83856
83857             var annotation = container.selectAll('.field-label .label-textannotation');
83858             var icon = annotation.selectAll('.icon').data(_locked ? [0] : []);
83859             icon.exit().remove();
83860             icon.enter().append('svg').attr('class', 'icon').append('use').attr('xlink:href', '#fas-lock');
83861             container.call(_locked ? _lockedTip : _lockedTip.destroy);
83862           };
83863
83864           field.state = function (val) {
83865             if (!arguments.length) return _state;
83866             _state = val;
83867             return field;
83868           };
83869
83870           field.tags = function (val) {
83871             if (!arguments.length) return _tags;
83872             _tags = val;
83873
83874             if (tagsContainFieldKey() && !_show) {
83875               // always show a field if it has a value to display
83876               _show = true;
83877
83878               if (!field.impl) {
83879                 createField();
83880               }
83881             }
83882
83883             return field;
83884           };
83885
83886           field.locked = function (val) {
83887             if (!arguments.length) return _locked;
83888             _locked = val;
83889             return field;
83890           };
83891
83892           field.show = function () {
83893             _show = true;
83894
83895             if (!field.impl) {
83896               createField();
83897             }
83898
83899             if (field["default"] && field.key && _tags[field.key] !== field["default"]) {
83900               var t = {};
83901               t[field.key] = field["default"];
83902               dispatch.call('change', this, t);
83903             }
83904           }; // A shown field has a visible UI, a non-shown field is in the 'Add field' dropdown
83905
83906
83907           field.isShown = function () {
83908             return _show;
83909           }; // An allowed field can appear in the UI or in the 'Add field' dropdown.
83910           // A non-allowed field is hidden from the user altogether
83911
83912
83913           field.isAllowed = function () {
83914             if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return false;
83915             if (field.geometry && !entityIDs.every(function (entityID) {
83916               return field.matchGeometry(context.graph().geometry(entityID));
83917             })) return false;
83918
83919             if (entityIDs && _entityExtent && field.locationSetID) {
83920               // is field allowed in this location?
83921               var validLocations = _mainLocations.locationsAt(_entityExtent.center());
83922               if (!validLocations[field.locationSetID]) return false;
83923             }
83924
83925             var prerequisiteTag = field.prerequisiteTag;
83926
83927             if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
83928             prerequisiteTag) {
83929               if (!entityIDs.every(function (entityID) {
83930                 var entity = context.graph().entity(entityID);
83931
83932                 if (prerequisiteTag.key) {
83933                   var value = entity.tags[prerequisiteTag.key];
83934                   if (!value) return false;
83935
83936                   if (prerequisiteTag.valueNot) {
83937                     return prerequisiteTag.valueNot !== value;
83938                   }
83939
83940                   if (prerequisiteTag.value) {
83941                     return prerequisiteTag.value === value;
83942                   }
83943                 } else if (prerequisiteTag.keyNot) {
83944                   if (entity.tags[prerequisiteTag.keyNot]) return false;
83945                 }
83946
83947                 return true;
83948               })) return false;
83949             }
83950
83951             return true;
83952           };
83953
83954           field.focus = function () {
83955             if (field.impl) {
83956               field.impl.focus();
83957             }
83958           };
83959
83960           return utilRebind(field, dispatch, 'on');
83961         }
83962
83963         function uiFormFields(context) {
83964           var moreCombo = uiCombobox(context, 'more-fields').minItems(1);
83965           var _fieldsArr = [];
83966           var _lastPlaceholder = '';
83967           var _state = '';
83968           var _klass = '';
83969
83970           function formFields(selection) {
83971             var allowedFields = _fieldsArr.filter(function (field) {
83972               return field.isAllowed();
83973             });
83974
83975             var shown = allowedFields.filter(function (field) {
83976               return field.isShown();
83977             });
83978             var notShown = allowedFields.filter(function (field) {
83979               return !field.isShown();
83980             });
83981             var container = selection.selectAll('.form-fields-container').data([0]);
83982             container = container.enter().append('div').attr('class', 'form-fields-container ' + (_klass || '')).merge(container);
83983             var fields = container.selectAll('.wrap-form-field').data(shown, function (d) {
83984               return d.id + (d.entityIDs ? d.entityIDs.join() : '');
83985             });
83986             fields.exit().remove(); // Enter
83987
83988             var enter = fields.enter().append('div').attr('class', function (d) {
83989               return 'wrap-form-field wrap-form-field-' + d.safeid;
83990             }); // Update
83991
83992             fields = fields.merge(enter);
83993             fields.order().each(function (d) {
83994               select(this).call(d.render);
83995             });
83996             var titles = [];
83997             var moreFields = notShown.map(function (field) {
83998               var title = field.title();
83999               titles.push(title);
84000               var terms = field.terms();
84001               if (field.key) terms.push(field.key);
84002               if (field.keys) terms = terms.concat(field.keys);
84003               return {
84004                 display: field.label(),
84005                 value: title,
84006                 title: title,
84007                 field: field,
84008                 terms: terms
84009               };
84010             });
84011             var placeholder = titles.slice(0, 3).join(', ') + (titles.length > 3 ? '…' : '');
84012             var more = selection.selectAll('.more-fields').data(_state === 'hover' || moreFields.length === 0 ? [] : [0]);
84013             more.exit().remove();
84014             var moreEnter = more.enter().append('div').attr('class', 'more-fields').append('label');
84015             moreEnter.append('span').html(_t.html('inspector.add_fields'));
84016             more = moreEnter.merge(more);
84017             var input = more.selectAll('.value').data([0]);
84018             input.exit().remove();
84019             input = input.enter().append('input').attr('class', 'value').attr('type', 'text').attr('placeholder', placeholder).call(utilNoAuto).merge(input);
84020             input.call(utilGetSetValue, '').call(moreCombo.data(moreFields).on('accept', function (d) {
84021               if (!d) return; // user entered something that was not matched
84022
84023               var field = d.field;
84024               field.show();
84025               selection.call(formFields); // rerender
84026
84027               field.focus();
84028             })); // avoid updating placeholder excessively (triggers style recalc)
84029
84030             if (_lastPlaceholder !== placeholder) {
84031               input.attr('placeholder', placeholder);
84032               _lastPlaceholder = placeholder;
84033             }
84034           }
84035
84036           formFields.fieldsArr = function (val) {
84037             if (!arguments.length) return _fieldsArr;
84038             _fieldsArr = val || [];
84039             return formFields;
84040           };
84041
84042           formFields.state = function (val) {
84043             if (!arguments.length) return _state;
84044             _state = val;
84045             return formFields;
84046           };
84047
84048           formFields.klass = function (val) {
84049             if (!arguments.length) return _klass;
84050             _klass = val;
84051             return formFields;
84052           };
84053
84054           return formFields;
84055         }
84056
84057         function uiSectionPresetFields(context) {
84058           var section = uiSection('preset-fields', context).label(_t.html('inspector.fields')).disclosureContent(renderDisclosureContent);
84059           var dispatch = dispatch$8('change', 'revert');
84060           var formFields = uiFormFields(context);
84061
84062           var _state;
84063
84064           var _fieldsArr;
84065
84066           var _presets = [];
84067
84068           var _tags;
84069
84070           var _entityIDs;
84071
84072           function renderDisclosureContent(selection) {
84073             if (!_fieldsArr) {
84074               var graph = context.graph();
84075               var geometries = Object.keys(_entityIDs.reduce(function (geoms, entityID) {
84076                 geoms[graph.entity(entityID).geometry(graph)] = true;
84077                 return geoms;
84078               }, {}));
84079               var presetsManager = _mainPresetIndex;
84080               var allFields = [];
84081               var allMoreFields = [];
84082               var sharedTotalFields;
84083
84084               _presets.forEach(function (preset) {
84085                 var fields = preset.fields();
84086                 var moreFields = preset.moreFields();
84087                 allFields = utilArrayUnion(allFields, fields);
84088                 allMoreFields = utilArrayUnion(allMoreFields, moreFields);
84089
84090                 if (!sharedTotalFields) {
84091                   sharedTotalFields = utilArrayUnion(fields, moreFields);
84092                 } else {
84093                   sharedTotalFields = sharedTotalFields.filter(function (field) {
84094                     return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
84095                   });
84096                 }
84097               });
84098
84099               var sharedFields = allFields.filter(function (field) {
84100                 return sharedTotalFields.indexOf(field) !== -1;
84101               });
84102               var sharedMoreFields = allMoreFields.filter(function (field) {
84103                 return sharedTotalFields.indexOf(field) !== -1;
84104               });
84105               _fieldsArr = [];
84106               sharedFields.forEach(function (field) {
84107                 if (field.matchAllGeometry(geometries)) {
84108                   _fieldsArr.push(uiField(context, field, _entityIDs));
84109                 }
84110               });
84111               var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
84112
84113               if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field('restrictions')) {
84114                 _fieldsArr.push(uiField(context, presetsManager.field('restrictions'), _entityIDs));
84115               }
84116
84117               var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
84118               additionalFields.sort(function (field1, field2) {
84119                 return field1.label().localeCompare(field2.label(), _mainLocalizer.localeCode());
84120               });
84121               additionalFields.forEach(function (field) {
84122                 if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
84123                   _fieldsArr.push(uiField(context, field, _entityIDs, {
84124                     show: false
84125                   }));
84126                 }
84127               });
84128
84129               _fieldsArr.forEach(function (field) {
84130                 field.on('change', function (t, onInput) {
84131                   dispatch.call('change', field, _entityIDs, t, onInput);
84132                 }).on('revert', function (keys) {
84133                   dispatch.call('revert', field, keys);
84134                 });
84135               });
84136             }
84137
84138             _fieldsArr.forEach(function (field) {
84139               field.state(_state).tags(_tags);
84140             });
84141
84142             selection.call(formFields.fieldsArr(_fieldsArr).state(_state).klass('grouped-items-area'));
84143             selection.selectAll('.wrap-form-field input').on('keydown', function (d3_event) {
84144               // if user presses enter, and combobox is not active, accept edits..
84145               if (d3_event.keyCode === 13 && // ↩ Return
84146               context.container().select('.combobox').empty()) {
84147                 context.enter(modeBrowse(context));
84148               }
84149             });
84150           }
84151
84152           section.presets = function (val) {
84153             if (!arguments.length) return _presets;
84154
84155             if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
84156               _presets = val;
84157               _fieldsArr = null;
84158             }
84159
84160             return section;
84161           };
84162
84163           section.state = function (val) {
84164             if (!arguments.length) return _state;
84165             _state = val;
84166             return section;
84167           };
84168
84169           section.tags = function (val) {
84170             if (!arguments.length) return _tags;
84171             _tags = val; // Don't reset _fieldsArr here.
84172
84173             return section;
84174           };
84175
84176           section.entityIDs = function (val) {
84177             if (!arguments.length) return _entityIDs;
84178
84179             if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
84180               _entityIDs = val;
84181               _fieldsArr = null;
84182             }
84183
84184             return section;
84185           };
84186
84187           return utilRebind(section, dispatch, 'on');
84188         }
84189
84190         function uiSectionRawMemberEditor(context) {
84191           var section = uiSection('raw-member-editor', context).shouldDisplay(function () {
84192             if (!_entityIDs || _entityIDs.length !== 1) return false;
84193             var entity = context.hasEntity(_entityIDs[0]);
84194             return entity && entity.type === 'relation';
84195           }).label(function () {
84196             var entity = context.hasEntity(_entityIDs[0]);
84197             if (!entity) return '';
84198             var gt = entity.members.length > _maxMembers ? '>' : '';
84199             var count = gt + entity.members.slice(0, _maxMembers).length;
84200             return _t('inspector.title_count', {
84201               title: _t.html('inspector.members'),
84202               count: count
84203             });
84204           }).disclosureContent(renderDisclosureContent);
84205           var taginfo = services.taginfo;
84206
84207           var _entityIDs;
84208
84209           var _maxMembers = 1000;
84210
84211           function downloadMember(d3_event, d) {
84212             d3_event.preventDefault(); // display the loading indicator
84213
84214             select(this.parentNode).classed('tag-reference-loading', true);
84215             context.loadEntity(d.id, function () {
84216               section.reRender();
84217             });
84218           }
84219
84220           function zoomToMember(d3_event, d) {
84221             d3_event.preventDefault();
84222             var entity = context.entity(d.id);
84223             context.map().zoomToEase(entity); // highlight the feature in case it wasn't previously on-screen
84224
84225             utilHighlightEntities([d.id], true, context);
84226           }
84227
84228           function selectMember(d3_event, d) {
84229             d3_event.preventDefault(); // remove the hover-highlight styling
84230
84231             utilHighlightEntities([d.id], false, context);
84232             var entity = context.entity(d.id);
84233             var mapExtent = context.map().extent();
84234
84235             if (!entity.intersects(mapExtent, context.graph())) {
84236               // zoom to the entity if its extent is not visible now
84237               context.map().zoomToEase(entity);
84238             }
84239
84240             context.enter(modeSelect(context, [d.id]));
84241           }
84242
84243           function changeRole(d3_event, d) {
84244             var oldRole = d.role;
84245             var newRole = context.cleanRelationRole(select(this).property('value'));
84246
84247             if (oldRole !== newRole) {
84248               var member = {
84249                 id: d.id,
84250                 type: d.type,
84251                 role: newRole
84252               };
84253               context.perform(actionChangeMember(d.relation.id, member, d.index), _t('operations.change_role.annotation', {
84254                 n: 1
84255               }));
84256               context.validator().validate();
84257             }
84258           }
84259
84260           function deleteMember(d3_event, d) {
84261             // remove the hover-highlight styling
84262             utilHighlightEntities([d.id], false, context);
84263             context.perform(actionDeleteMember(d.relation.id, d.index), _t('operations.delete_member.annotation', {
84264               n: 1
84265             }));
84266
84267             if (!context.hasEntity(d.relation.id)) {
84268               // Removing the last member will also delete the relation.
84269               // If this happens we need to exit the selection mode
84270               context.enter(modeBrowse(context));
84271             } else {
84272               // Changing the mode also runs `validate`, but otherwise we need to
84273               // rerun it manually
84274               context.validator().validate();
84275             }
84276           }
84277
84278           function renderDisclosureContent(selection) {
84279             var entityID = _entityIDs[0];
84280             var memberships = [];
84281             var entity = context.entity(entityID);
84282             entity.members.slice(0, _maxMembers).forEach(function (member, index) {
84283               memberships.push({
84284                 index: index,
84285                 id: member.id,
84286                 type: member.type,
84287                 role: member.role,
84288                 relation: entity,
84289                 member: context.hasEntity(member.id),
84290                 domId: utilUniqueDomId(entityID + '-member-' + index)
84291               });
84292             });
84293             var list = selection.selectAll('.member-list').data([0]);
84294             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
84295             var items = list.selectAll('li').data(memberships, function (d) {
84296               return osmEntity.key(d.relation) + ',' + d.index + ',' + (d.member ? osmEntity.key(d.member) : 'incomplete');
84297             });
84298             items.exit().each(unbind).remove();
84299             var itemsEnter = items.enter().append('li').attr('class', 'member-row form-field').classed('member-incomplete', function (d) {
84300               return !d.member;
84301             });
84302             itemsEnter.each(function (d) {
84303               var item = select(this);
84304               var label = item.append('label').attr('class', 'field-label').attr('for', d.domId);
84305
84306               if (d.member) {
84307                 // highlight the member feature in the map while hovering on the list item
84308                 item.on('mouseover', function () {
84309                   utilHighlightEntities([d.id], true, context);
84310                 }).on('mouseout', function () {
84311                   utilHighlightEntities([d.id], false, context);
84312                 });
84313                 var labelLink = label.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectMember);
84314                 labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
84315                   var matched = _mainPresetIndex.match(d.member, context.graph());
84316                   return matched && matched.name() || utilDisplayType(d.member.id);
84317                 });
84318                 labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
84319                   return utilDisplayName(d.member);
84320                 });
84321                 label.append('button').attr('title', _t('icons.remove')).attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete'));
84322                 label.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToMember);
84323               } else {
84324                 var labelText = label.append('span').attr('class', 'label-text');
84325                 labelText.append('span').attr('class', 'member-entity-type').html(_t.html('inspector.' + d.type, {
84326                   id: d.id
84327                 }));
84328                 labelText.append('span').attr('class', 'member-entity-name').html(_t.html('inspector.incomplete', {
84329                   id: d.id
84330                 }));
84331                 label.append('button').attr('class', 'member-download').attr('title', _t('icons.download')).call(svgIcon('#iD-icon-load')).on('click', downloadMember);
84332               }
84333             });
84334             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
84335             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
84336               return d.domId;
84337             }).property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto);
84338
84339             if (taginfo) {
84340               wrapEnter.each(bindTypeahead);
84341             } // update
84342
84343
84344             items = items.merge(itemsEnter).order();
84345             items.select('input.member-role').property('value', function (d) {
84346               return d.role;
84347             }).on('blur', changeRole).on('change', changeRole);
84348             items.select('button.member-delete').on('click', deleteMember);
84349             var dragOrigin, targetIndex;
84350             items.call(d3_drag().on('start', function (d3_event) {
84351               dragOrigin = {
84352                 x: d3_event.x,
84353                 y: d3_event.y
84354               };
84355               targetIndex = null;
84356             }).on('drag', function (d3_event) {
84357               var x = d3_event.x - dragOrigin.x,
84358                   y = d3_event.y - dragOrigin.y;
84359               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
84360               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
84361               var index = items.nodes().indexOf(this);
84362               select(this).classed('dragging', true);
84363               targetIndex = null;
84364               selection.selectAll('li.member-row').style('transform', function (d2, index2) {
84365                 var node = select(this).node();
84366
84367                 if (index === index2) {
84368                   return 'translate(' + x + 'px, ' + y + 'px)';
84369                 } else if (index2 > index && d3_event.y > node.offsetTop) {
84370                   if (targetIndex === null || index2 > targetIndex) {
84371                     targetIndex = index2;
84372                   }
84373
84374                   return 'translateY(-100%)';
84375                 } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
84376                   if (targetIndex === null || index2 < targetIndex) {
84377                     targetIndex = index2;
84378                   }
84379
84380                   return 'translateY(100%)';
84381                 }
84382
84383                 return null;
84384               });
84385             }).on('end', function (d3_event, d) {
84386               if (!select(this).classed('dragging')) return;
84387               var index = items.nodes().indexOf(this);
84388               select(this).classed('dragging', false);
84389               selection.selectAll('li.member-row').style('transform', null);
84390
84391               if (targetIndex !== null) {
84392                 // dragged to a new position, reorder
84393                 context.perform(actionMoveMember(d.relation.id, index, targetIndex), _t('operations.reorder_members.annotation'));
84394                 context.validator().validate();
84395               }
84396             }));
84397
84398             function bindTypeahead(d) {
84399               var row = select(this);
84400               var role = row.selectAll('input.member-role');
84401               var origValue = role.property('value');
84402
84403               function sort(value, data) {
84404                 var sameletter = [];
84405                 var other = [];
84406
84407                 for (var i = 0; i < data.length; i++) {
84408                   if (data[i].value.substring(0, value.length) === value) {
84409                     sameletter.push(data[i]);
84410                   } else {
84411                     other.push(data[i]);
84412                   }
84413                 }
84414
84415                 return sameletter.concat(other);
84416               }
84417
84418               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
84419                 // The `geometry` param is used in the `taginfo.js` interface for
84420                 // filtering results, as a key into the `tag_members_fractions`
84421                 // object.  If we don't know the geometry because the member is
84422                 // not yet downloaded, it's ok to guess based on type.
84423                 var geometry;
84424
84425                 if (d.member) {
84426                   geometry = context.graph().geometry(d.member.id);
84427                 } else if (d.type === 'relation') {
84428                   geometry = 'relation';
84429                 } else if (d.type === 'way') {
84430                   geometry = 'line';
84431                 } else {
84432                   geometry = 'point';
84433                 }
84434
84435                 var rtype = entity.tags.type;
84436                 taginfo.roles({
84437                   debounce: true,
84438                   rtype: rtype || '',
84439                   geometry: geometry,
84440                   query: role
84441                 }, function (err, data) {
84442                   if (!err) callback(sort(role, data));
84443                 });
84444               }).on('cancel', function () {
84445                 role.property('value', origValue);
84446               }));
84447             }
84448
84449             function unbind() {
84450               var row = select(this);
84451               row.selectAll('input.member-role').call(uiCombobox.off, context);
84452             }
84453           }
84454
84455           section.entityIDs = function (val) {
84456             if (!arguments.length) return _entityIDs;
84457             _entityIDs = val;
84458             return section;
84459           };
84460
84461           return section;
84462         }
84463
84464         function actionDeleteMembers(relationId, memberIndexes) {
84465           return function (graph) {
84466             // Remove the members in descending order so removals won't shift what members
84467             // are at the remaining indexes
84468             memberIndexes.sort(function (a, b) {
84469               return b - a;
84470             });
84471
84472             for (var i in memberIndexes) {
84473               graph = actionDeleteMember(relationId, memberIndexes[i])(graph);
84474             }
84475
84476             return graph;
84477           };
84478         }
84479
84480         function uiSectionRawMembershipEditor(context) {
84481           var section = uiSection('raw-membership-editor', context).shouldDisplay(function () {
84482             return _entityIDs && _entityIDs.length;
84483           }).label(function () {
84484             var parents = getSharedParentRelations();
84485             var gt = parents.length > _maxMemberships ? '>' : '';
84486             var count = gt + parents.slice(0, _maxMemberships).length;
84487             return _t('inspector.title_count', {
84488               title: _t.html('inspector.relations'),
84489               count: count
84490             });
84491           }).disclosureContent(renderDisclosureContent);
84492           var taginfo = services.taginfo;
84493           var nearbyCombo = uiCombobox(context, 'parent-relation').minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function (d3_event, d) {
84494             if (d.relation) utilHighlightEntities([d.relation.id], true, context);
84495           }).itemsMouseLeave(function (d3_event, d) {
84496             if (d.relation) utilHighlightEntities([d.relation.id], false, context);
84497           });
84498           var _inChange = false;
84499           var _entityIDs = [];
84500
84501           var _showBlank;
84502
84503           var _maxMemberships = 1000;
84504
84505           function getSharedParentRelations() {
84506             var parents = [];
84507
84508             for (var i = 0; i < _entityIDs.length; i++) {
84509               var entity = context.graph().hasEntity(_entityIDs[i]);
84510               if (!entity) continue;
84511
84512               if (i === 0) {
84513                 parents = context.graph().parentRelations(entity);
84514               } else {
84515                 parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
84516               }
84517
84518               if (!parents.length) break;
84519             }
84520
84521             return parents;
84522           }
84523
84524           function getMemberships() {
84525             var memberships = [];
84526             var relations = getSharedParentRelations().slice(0, _maxMemberships);
84527             var isMultiselect = _entityIDs.length > 1;
84528             var i, relation, membership, index, member, indexedMember;
84529
84530             for (i = 0; i < relations.length; i++) {
84531               relation = relations[i];
84532               membership = {
84533                 relation: relation,
84534                 members: [],
84535                 hash: osmEntity.key(relation)
84536               };
84537
84538               for (index = 0; index < relation.members.length; index++) {
84539                 member = relation.members[index];
84540
84541                 if (_entityIDs.indexOf(member.id) !== -1) {
84542                   indexedMember = Object.assign({}, member, {
84543                     index: index
84544                   });
84545                   membership.members.push(indexedMember);
84546                   membership.hash += ',' + index.toString();
84547
84548                   if (!isMultiselect) {
84549                     // For single selections, list one entry per membership per relation.
84550                     // For multiselections, list one entry per relation.
84551                     memberships.push(membership);
84552                     membership = {
84553                       relation: relation,
84554                       members: [],
84555                       hash: osmEntity.key(relation)
84556                     };
84557                   }
84558                 }
84559               }
84560
84561               if (membership.members.length) memberships.push(membership);
84562             }
84563
84564             memberships.forEach(function (membership) {
84565               membership.domId = utilUniqueDomId('membership-' + membership.relation.id);
84566               var roles = [];
84567               membership.members.forEach(function (member) {
84568                 if (roles.indexOf(member.role) === -1) roles.push(member.role);
84569               });
84570               membership.role = roles.length === 1 ? roles[0] : roles;
84571             });
84572             return memberships;
84573           }
84574
84575           function selectRelation(d3_event, d) {
84576             d3_event.preventDefault(); // remove the hover-highlight styling
84577
84578             utilHighlightEntities([d.relation.id], false, context);
84579             context.enter(modeSelect(context, [d.relation.id]));
84580           }
84581
84582           function zoomToRelation(d3_event, d) {
84583             d3_event.preventDefault();
84584             var entity = context.entity(d.relation.id);
84585             context.map().zoomToEase(entity); // highlight the relation in case it wasn't previously on-screen
84586
84587             utilHighlightEntities([d.relation.id], true, context);
84588           }
84589
84590           function changeRole(d3_event, d) {
84591             if (d === 0) return; // called on newrow (shouldn't happen)
84592
84593             if (_inChange) return; // avoid accidental recursive call #5731
84594
84595             var newRole = context.cleanRelationRole(select(this).property('value'));
84596             if (!newRole.trim() && typeof d.role !== 'string') return;
84597             var membersToUpdate = d.members.filter(function (member) {
84598               return member.role !== newRole;
84599             });
84600
84601             if (membersToUpdate.length) {
84602               _inChange = true;
84603               context.perform(function actionChangeMemberRoles(graph) {
84604                 membersToUpdate.forEach(function (member) {
84605                   var newMember = Object.assign({}, member, {
84606                     role: newRole
84607                   });
84608                   delete newMember.index;
84609                   graph = actionChangeMember(d.relation.id, newMember, member.index)(graph);
84610                 });
84611                 return graph;
84612               }, _t('operations.change_role.annotation', {
84613                 n: membersToUpdate.length
84614               }));
84615               context.validator().validate();
84616             }
84617
84618             _inChange = false;
84619           }
84620
84621           function addMembership(d, role) {
84622             this.blur(); // avoid keeping focus on the button
84623
84624             _showBlank = false;
84625
84626             function actionAddMembers(relationId, ids, role) {
84627               return function (graph) {
84628                 for (var i in ids) {
84629                   var member = {
84630                     id: ids[i],
84631                     type: graph.entity(ids[i]).type,
84632                     role: role
84633                   };
84634                   graph = actionAddMember(relationId, member)(graph);
84635                 }
84636
84637                 return graph;
84638               };
84639             }
84640
84641             if (d.relation) {
84642               context.perform(actionAddMembers(d.relation.id, _entityIDs, role), _t('operations.add_member.annotation', {
84643                 n: _entityIDs.length
84644               }));
84645               context.validator().validate();
84646             } else {
84647               var relation = osmRelation();
84648               context.perform(actionAddEntity(relation), actionAddMembers(relation.id, _entityIDs, role), _t('operations.add.annotation.relation')); // changing the mode also runs `validate`
84649
84650               context.enter(modeSelect(context, [relation.id]).newFeature(true));
84651             }
84652           }
84653
84654           function deleteMembership(d3_event, d) {
84655             this.blur(); // avoid keeping focus on the button
84656
84657             if (d === 0) return; // called on newrow (shouldn't happen)
84658             // remove the hover-highlight styling
84659
84660             utilHighlightEntities([d.relation.id], false, context);
84661             var indexes = d.members.map(function (member) {
84662               return member.index;
84663             });
84664             context.perform(actionDeleteMembers(d.relation.id, indexes), _t('operations.delete_member.annotation', {
84665               n: _entityIDs.length
84666             }));
84667             context.validator().validate();
84668           }
84669
84670           function fetchNearbyRelations(q, callback) {
84671             var newRelation = {
84672               relation: null,
84673               value: _t('inspector.new_relation'),
84674               display: _t.html('inspector.new_relation')
84675             };
84676             var entityID = _entityIDs[0];
84677             var result = [];
84678             var graph = context.graph();
84679
84680             function baseDisplayLabel(entity) {
84681               var matched = _mainPresetIndex.match(entity, graph);
84682               var presetName = matched && matched.name() || _t('inspector.relation');
84683               var entityName = utilDisplayName(entity) || '';
84684               return presetName + ' ' + entityName;
84685             }
84686
84687             var explicitRelation = q && context.hasEntity(q.toLowerCase());
84688
84689             if (explicitRelation && explicitRelation.type === 'relation' && explicitRelation.id !== entityID) {
84690               // loaded relation is specified explicitly, only show that
84691               result.push({
84692                 relation: explicitRelation,
84693                 value: baseDisplayLabel(explicitRelation) + ' ' + explicitRelation.id
84694               });
84695             } else {
84696               context.history().intersects(context.map().extent()).forEach(function (entity) {
84697                 if (entity.type !== 'relation' || entity.id === entityID) return;
84698                 var value = baseDisplayLabel(entity);
84699                 if (q && (value + ' ' + entity.id).toLowerCase().indexOf(q.toLowerCase()) === -1) return;
84700                 result.push({
84701                   relation: entity,
84702                   value: value
84703                 });
84704               });
84705               result.sort(function (a, b) {
84706                 return osmRelation.creationOrder(a.relation, b.relation);
84707               }); // Dedupe identical names by appending relation id - see #2891
84708
84709               var dupeGroups = Object.values(utilArrayGroupBy(result, 'value')).filter(function (v) {
84710                 return v.length > 1;
84711               });
84712               dupeGroups.forEach(function (group) {
84713                 group.forEach(function (obj) {
84714                   obj.value += ' ' + obj.relation.id;
84715                 });
84716               });
84717             }
84718
84719             result.forEach(function (obj) {
84720               obj.title = obj.value;
84721             });
84722             result.unshift(newRelation);
84723             callback(result);
84724           }
84725
84726           function renderDisclosureContent(selection) {
84727             var memberships = getMemberships();
84728             var list = selection.selectAll('.member-list').data([0]);
84729             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
84730             var items = list.selectAll('li.member-row-normal').data(memberships, function (d) {
84731               return d.hash;
84732             });
84733             items.exit().each(unbind).remove(); // Enter
84734
84735             var itemsEnter = items.enter().append('li').attr('class', 'member-row member-row-normal form-field'); // highlight the relation in the map while hovering on the list item
84736
84737             itemsEnter.on('mouseover', function (d3_event, d) {
84738               utilHighlightEntities([d.relation.id], true, context);
84739             }).on('mouseout', function (d3_event, d) {
84740               utilHighlightEntities([d.relation.id], false, context);
84741             });
84742             var labelEnter = itemsEnter.append('label').attr('class', 'field-label').attr('for', function (d) {
84743               return d.domId;
84744             });
84745             var labelLink = labelEnter.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectRelation);
84746             labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
84747               var matched = _mainPresetIndex.match(d.relation, context.graph());
84748               return matched && matched.name() || _t('inspector.relation');
84749             });
84750             labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
84751               return utilDisplayName(d.relation);
84752             });
84753             labelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', deleteMembership);
84754             labelEnter.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToRelation);
84755             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
84756             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
84757               return d.domId;
84758             }).property('type', 'text').property('value', function (d) {
84759               return typeof d.role === 'string' ? d.role : '';
84760             }).attr('title', function (d) {
84761               return Array.isArray(d.role) ? d.role.filter(Boolean).join('\n') : d.role;
84762             }).attr('placeholder', function (d) {
84763               return Array.isArray(d.role) ? _t('inspector.multiple_roles') : _t('inspector.role');
84764             }).classed('mixed', function (d) {
84765               return Array.isArray(d.role);
84766             }).call(utilNoAuto).on('blur', changeRole).on('change', changeRole);
84767
84768             if (taginfo) {
84769               wrapEnter.each(bindTypeahead);
84770             }
84771
84772             var newMembership = list.selectAll('.member-row-new').data(_showBlank ? [0] : []); // Exit
84773
84774             newMembership.exit().remove(); // Enter
84775
84776             var newMembershipEnter = newMembership.enter().append('li').attr('class', 'member-row member-row-new form-field');
84777             var newLabelEnter = newMembershipEnter.append('label').attr('class', 'field-label');
84778             newLabelEnter.append('input').attr('placeholder', _t('inspector.choose_relation')).attr('type', 'text').attr('class', 'member-entity-input').call(utilNoAuto);
84779             newLabelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', function () {
84780               list.selectAll('.member-row-new').remove();
84781             });
84782             var newWrapEnter = newMembershipEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
84783             newWrapEnter.append('input').attr('class', 'member-role').property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto); // Update
84784
84785             newMembership = newMembership.merge(newMembershipEnter);
84786             newMembership.selectAll('.member-entity-input').on('blur', cancelEntity) // if it wasn't accepted normally, cancel it
84787             .call(nearbyCombo.on('accept', acceptEntity).on('cancel', cancelEntity)); // Container for the Add button
84788
84789             var addRow = selection.selectAll('.add-row').data([0]); // enter
84790
84791             var addRowEnter = addRow.enter().append('div').attr('class', 'add-row');
84792             var addRelationButton = addRowEnter.append('button').attr('class', 'add-relation');
84793             addRelationButton.call(svgIcon('#iD-icon-plus', 'light'));
84794             addRelationButton.call(uiTooltip().title(_t.html('inspector.add_to_relation')).placement(_mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left'));
84795             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
84796
84797             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
84798             // update
84799
84800             addRow = addRow.merge(addRowEnter);
84801             addRow.select('.add-relation').on('click', function () {
84802               _showBlank = true;
84803               section.reRender();
84804               list.selectAll('.member-entity-input').node().focus();
84805             });
84806
84807             function acceptEntity(d) {
84808               if (!d) {
84809                 cancelEntity();
84810                 return;
84811               } // remove hover-higlighting
84812
84813
84814               if (d.relation) utilHighlightEntities([d.relation.id], false, context);
84815               var role = context.cleanRelationRole(list.selectAll('.member-row-new .member-role').property('value'));
84816               addMembership(d, role);
84817             }
84818
84819             function cancelEntity() {
84820               var input = newMembership.selectAll('.member-entity-input');
84821               input.property('value', ''); // remove hover-higlighting
84822
84823               context.surface().selectAll('.highlighted').classed('highlighted', false);
84824             }
84825
84826             function bindTypeahead(d) {
84827               var row = select(this);
84828               var role = row.selectAll('input.member-role');
84829               var origValue = role.property('value');
84830
84831               function sort(value, data) {
84832                 var sameletter = [];
84833                 var other = [];
84834
84835                 for (var i = 0; i < data.length; i++) {
84836                   if (data[i].value.substring(0, value.length) === value) {
84837                     sameletter.push(data[i]);
84838                   } else {
84839                     other.push(data[i]);
84840                   }
84841                 }
84842
84843                 return sameletter.concat(other);
84844               }
84845
84846               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
84847                 var rtype = d.relation.tags.type;
84848                 taginfo.roles({
84849                   debounce: true,
84850                   rtype: rtype || '',
84851                   geometry: context.graph().geometry(_entityIDs[0]),
84852                   query: role
84853                 }, function (err, data) {
84854                   if (!err) callback(sort(role, data));
84855                 });
84856               }).on('cancel', function () {
84857                 role.property('value', origValue);
84858               }));
84859             }
84860
84861             function unbind() {
84862               var row = select(this);
84863               row.selectAll('input.member-role').call(uiCombobox.off, context);
84864             }
84865           }
84866
84867           section.entityIDs = function (val) {
84868             if (!arguments.length) return _entityIDs;
84869             _entityIDs = val;
84870             _showBlank = false;
84871             return section;
84872           };
84873
84874           return section;
84875         }
84876
84877         function uiSectionSelectionList(context) {
84878           var _selectedIDs = [];
84879           var section = uiSection('selected-features', context).shouldDisplay(function () {
84880             return _selectedIDs.length > 1;
84881           }).label(function () {
84882             return _t('inspector.title_count', {
84883               title: _t.html('inspector.features'),
84884               count: _selectedIDs.length
84885             });
84886           }).disclosureContent(renderDisclosureContent);
84887           context.history().on('change.selectionList', function (difference) {
84888             if (difference) {
84889               section.reRender();
84890             }
84891           });
84892
84893           section.entityIDs = function (val) {
84894             if (!arguments.length) return _selectedIDs;
84895             _selectedIDs = val;
84896             return section;
84897           };
84898
84899           function selectEntity(d3_event, entity) {
84900             context.enter(modeSelect(context, [entity.id]));
84901           }
84902
84903           function deselectEntity(d3_event, entity) {
84904             var selectedIDs = _selectedIDs.slice();
84905
84906             var index = selectedIDs.indexOf(entity.id);
84907
84908             if (index > -1) {
84909               selectedIDs.splice(index, 1);
84910               context.enter(modeSelect(context, selectedIDs));
84911             }
84912           }
84913
84914           function renderDisclosureContent(selection) {
84915             var list = selection.selectAll('.feature-list').data([0]);
84916             list = list.enter().append('ul').attr('class', 'feature-list').merge(list);
84917
84918             var entities = _selectedIDs.map(function (id) {
84919               return context.hasEntity(id);
84920             }).filter(Boolean);
84921
84922             var items = list.selectAll('.feature-list-item').data(entities, osmEntity.key);
84923             items.exit().remove(); // Enter
84924
84925             var enter = items.enter().append('li').attr('class', 'feature-list-item').each(function (d) {
84926               select(this).on('mouseover', function () {
84927                 utilHighlightEntities([d.id], true, context);
84928               }).on('mouseout', function () {
84929                 utilHighlightEntities([d.id], false, context);
84930               });
84931             });
84932             var label = enter.append('button').attr('class', 'label').on('click', selectEntity);
84933             label.append('span').attr('class', 'entity-geom-icon').call(svgIcon('', 'pre-text'));
84934             label.append('span').attr('class', 'entity-type');
84935             label.append('span').attr('class', 'entity-name');
84936             enter.append('button').attr('class', 'close').attr('title', _t('icons.deselect')).on('click', deselectEntity).call(svgIcon('#iD-icon-close')); // Update
84937
84938             items = items.merge(enter);
84939             items.selectAll('.entity-geom-icon use').attr('href', function () {
84940               var entity = this.parentNode.parentNode.__data__;
84941               return '#iD-icon-' + entity.geometry(context.graph());
84942             });
84943             items.selectAll('.entity-type').html(function (entity) {
84944               return _mainPresetIndex.match(entity, context.graph()).name();
84945             });
84946             items.selectAll('.entity-name').html(function (d) {
84947               // fetch latest entity
84948               var entity = context.entity(d.id);
84949               return utilDisplayName(entity);
84950             });
84951           }
84952
84953           return section;
84954         }
84955
84956         function uiEntityEditor(context) {
84957           var dispatch = dispatch$8('choose');
84958           var _state = 'select';
84959           var _coalesceChanges = false;
84960           var _modified = false;
84961
84962           var _base;
84963
84964           var _entityIDs;
84965
84966           var _activePresets = [];
84967
84968           var _newFeature;
84969
84970           var _sections;
84971
84972           function entityEditor(selection) {
84973             var combinedTags = utilCombinedTags(_entityIDs, context.graph()); // Header
84974
84975             var header = selection.selectAll('.header').data([0]); // Enter
84976
84977             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
84978             headerEnter.append('button').attr('class', 'preset-reset preset-choose').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-forward' : '#iD-icon-backward'));
84979             headerEnter.append('button').attr('class', 'close').on('click', function () {
84980               context.enter(modeBrowse(context));
84981             }).call(svgIcon(_modified ? '#iD-icon-apply' : '#iD-icon-close'));
84982             headerEnter.append('h3'); // Update
84983
84984             header = header.merge(headerEnter);
84985             header.selectAll('h3').html(_entityIDs.length === 1 ? _t.html('inspector.edit') : _t.html('inspector.edit_features'));
84986             header.selectAll('.preset-reset').on('click', function () {
84987               dispatch.call('choose', this, _activePresets);
84988             }); // Body
84989
84990             var body = selection.selectAll('.inspector-body').data([0]); // Enter
84991
84992             var bodyEnter = body.enter().append('div').attr('class', 'entity-editor inspector-body sep-top'); // Update
84993
84994             body = body.merge(bodyEnter);
84995
84996             if (!_sections) {
84997               _sections = [uiSectionSelectionList(context), uiSectionFeatureType(context).on('choose', function (presets) {
84998                 dispatch.call('choose', this, presets);
84999               }), uiSectionEntityIssues(context), uiSectionPresetFields(context).on('change', changeTags).on('revert', revertTags), uiSectionRawTagEditor('raw-tag-editor', context).on('change', changeTags), uiSectionRawMemberEditor(context), uiSectionRawMembershipEditor(context)];
85000             }
85001
85002             _sections.forEach(function (section) {
85003               if (section.entityIDs) {
85004                 section.entityIDs(_entityIDs);
85005               }
85006
85007               if (section.presets) {
85008                 section.presets(_activePresets);
85009               }
85010
85011               if (section.tags) {
85012                 section.tags(combinedTags);
85013               }
85014
85015               if (section.state) {
85016                 section.state(_state);
85017               }
85018
85019               body.call(section.render);
85020             });
85021
85022             context.history().on('change.entity-editor', historyChanged);
85023
85024             function historyChanged(difference) {
85025               if (selection.selectAll('.entity-editor').empty()) return;
85026               if (_state === 'hide') return;
85027               var significant = !difference || difference.didChange.properties || difference.didChange.addition || difference.didChange.deletion;
85028               if (!significant) return;
85029               _entityIDs = _entityIDs.filter(context.hasEntity);
85030               if (!_entityIDs.length) return;
85031               var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
85032               loadActivePresets();
85033               var graph = context.graph();
85034               entityEditor.modified(_base !== graph);
85035               entityEditor(selection);
85036
85037               if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
85038                 // flash the button to indicate the preset changed
85039                 context.container().selectAll('.entity-editor button.preset-reset .label').style('background-color', '#fff').transition().duration(750).style('background-color', null);
85040               }
85041             }
85042           } // Tag changes that fire on input can all get coalesced into a single
85043           // history operation when the user leaves the field.  #2342
85044           // Use explicit entityIDs in case the selection changes before the event is fired.
85045
85046
85047           function changeTags(entityIDs, changed, onInput) {
85048             var actions = [];
85049
85050             for (var i in entityIDs) {
85051               var entityID = entityIDs[i];
85052               var entity = context.entity(entityID);
85053               var tags = Object.assign({}, entity.tags); // shallow copy
85054
85055               for (var k in changed) {
85056                 if (!k) continue;
85057                 var v = changed[k];
85058
85059                 if (v !== undefined || tags.hasOwnProperty(k)) {
85060                   tags[k] = v;
85061                 }
85062               }
85063
85064               if (!onInput) {
85065                 tags = utilCleanTags(tags);
85066               }
85067
85068               if (!fastDeepEqual(entity.tags, tags)) {
85069                 actions.push(actionChangeTags(entityID, tags));
85070               }
85071             }
85072
85073             if (actions.length) {
85074               var combinedAction = function combinedAction(graph) {
85075                 actions.forEach(function (action) {
85076                   graph = action(graph);
85077                 });
85078                 return graph;
85079               };
85080
85081               var annotation = _t('operations.change_tags.annotation');
85082
85083               if (_coalesceChanges) {
85084                 context.overwrite(combinedAction, annotation);
85085               } else {
85086                 context.perform(combinedAction, annotation);
85087                 _coalesceChanges = !!onInput;
85088               }
85089             } // if leaving field (blur event), rerun validation
85090
85091
85092             if (!onInput) {
85093               context.validator().validate();
85094             }
85095           }
85096
85097           function revertTags(keys) {
85098             var actions = [];
85099
85100             for (var i in _entityIDs) {
85101               var entityID = _entityIDs[i];
85102               var original = context.graph().base().entities[entityID];
85103               var changed = {};
85104
85105               for (var j in keys) {
85106                 var key = keys[j];
85107                 changed[key] = original ? original.tags[key] : undefined;
85108               }
85109
85110               var entity = context.entity(entityID);
85111               var tags = Object.assign({}, entity.tags); // shallow copy
85112
85113               for (var k in changed) {
85114                 if (!k) continue;
85115                 var v = changed[k];
85116
85117                 if (v !== undefined || tags.hasOwnProperty(k)) {
85118                   tags[k] = v;
85119                 }
85120               }
85121
85122               tags = utilCleanTags(tags);
85123
85124               if (!fastDeepEqual(entity.tags, tags)) {
85125                 actions.push(actionChangeTags(entityID, tags));
85126               }
85127             }
85128
85129             if (actions.length) {
85130               var combinedAction = function combinedAction(graph) {
85131                 actions.forEach(function (action) {
85132                   graph = action(graph);
85133                 });
85134                 return graph;
85135               };
85136
85137               var annotation = _t('operations.change_tags.annotation');
85138
85139               if (_coalesceChanges) {
85140                 context.overwrite(combinedAction, annotation);
85141               } else {
85142                 context.perform(combinedAction, annotation);
85143                 _coalesceChanges = false;
85144               }
85145             }
85146
85147             context.validator().validate();
85148           }
85149
85150           entityEditor.modified = function (val) {
85151             if (!arguments.length) return _modified;
85152             _modified = val;
85153             return entityEditor;
85154           };
85155
85156           entityEditor.state = function (val) {
85157             if (!arguments.length) return _state;
85158             _state = val;
85159             return entityEditor;
85160           };
85161
85162           entityEditor.entityIDs = function (val) {
85163             if (!arguments.length) return _entityIDs; // always reload these even if the entityIDs are unchanged, since we
85164             // could be reselecting after something like dragging a node
85165
85166             _base = context.graph();
85167             _coalesceChanges = false;
85168             if (val && _entityIDs && utilArrayIdentical(_entityIDs, val)) return entityEditor; // exit early if no change
85169
85170             _entityIDs = val;
85171             loadActivePresets(true);
85172             return entityEditor.modified(false);
85173           };
85174
85175           entityEditor.newFeature = function (val) {
85176             if (!arguments.length) return _newFeature;
85177             _newFeature = val;
85178             return entityEditor;
85179           };
85180
85181           function loadActivePresets(isForNewSelection) {
85182             var graph = context.graph();
85183             var counts = {};
85184
85185             for (var i in _entityIDs) {
85186               var entity = graph.hasEntity(_entityIDs[i]);
85187               if (!entity) return;
85188               var match = _mainPresetIndex.match(entity, graph);
85189               if (!counts[match.id]) counts[match.id] = 0;
85190               counts[match.id] += 1;
85191             }
85192
85193             var matches = Object.keys(counts).sort(function (p1, p2) {
85194               return counts[p2] - counts[p1];
85195             }).map(function (pID) {
85196               return _mainPresetIndex.item(pID);
85197             });
85198
85199             if (!isForNewSelection) {
85200               // A "weak" preset doesn't set any tags. (e.g. "Address")
85201               var weakPreset = _activePresets.length === 1 && !_activePresets[0].isFallback() && Object.keys(_activePresets[0].addTags || {}).length === 0; // Don't replace a weak preset with a fallback preset (e.g. "Point")
85202
85203               if (weakPreset && matches.length === 1 && matches[0].isFallback()) return;
85204             }
85205
85206             entityEditor.presets(matches);
85207           }
85208
85209           entityEditor.presets = function (val) {
85210             if (!arguments.length) return _activePresets; // don't reload the same preset
85211
85212             if (!utilArrayIdentical(val, _activePresets)) {
85213               _activePresets = val;
85214             }
85215
85216             return entityEditor;
85217           };
85218
85219           return utilRebind(entityEditor, dispatch, 'on');
85220         }
85221
85222         function uiPresetList(context) {
85223           var dispatch = dispatch$8('cancel', 'choose');
85224
85225           var _entityIDs;
85226
85227           var _currLoc;
85228
85229           var _currentPresets;
85230
85231           var _autofocus = false;
85232
85233           function presetList(selection) {
85234             if (!_entityIDs) return;
85235             var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
85236             selection.html('');
85237             var messagewrap = selection.append('div').attr('class', 'header fillL');
85238             var message = messagewrap.append('h3').html(_t.html('inspector.choose'));
85239             messagewrap.append('button').attr('class', 'preset-choose').on('click', function () {
85240               dispatch.call('cancel', this);
85241             }).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'));
85242
85243             function initialKeydown(d3_event) {
85244               // hack to let delete shortcut work when search is autofocused
85245               if (search.property('value').length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
85246                 d3_event.preventDefault();
85247                 d3_event.stopPropagation();
85248                 operationDelete(context, _entityIDs)(); // hack to let undo work when search is autofocused
85249               } else if (search.property('value').length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
85250                 d3_event.preventDefault();
85251                 d3_event.stopPropagation();
85252                 context.undo();
85253               } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
85254                 // don't check for delete/undo hack on future keydown events
85255                 select(this).on('keydown', keydown);
85256                 keydown.call(this, d3_event);
85257               }
85258             }
85259
85260             function keydown(d3_event) {
85261               // down arrow
85262               if (d3_event.keyCode === utilKeybinding.keyCodes['↓'] && // if insertion point is at the end of the string
85263               search.node().selectionStart === search.property('value').length) {
85264                 d3_event.preventDefault();
85265                 d3_event.stopPropagation(); // move focus to the first item in the preset list
85266
85267                 var buttons = list.selectAll('.preset-list-button');
85268                 if (!buttons.empty()) buttons.nodes()[0].focus();
85269               }
85270             }
85271
85272             function keypress(d3_event) {
85273               // enter
85274               var value = search.property('value');
85275
85276               if (d3_event.keyCode === 13 && // ↩ Return
85277               value.length) {
85278                 list.selectAll('.preset-list-item:first-child').each(function (d) {
85279                   d.choose.call(this);
85280                 });
85281               }
85282             }
85283
85284             function inputevent() {
85285               var value = search.property('value');
85286               list.classed('filtered', value.length);
85287               var results, messageText;
85288
85289               if (value.length) {
85290                 results = presets.search(value, entityGeometries()[0], _currLoc);
85291                 messageText = _t('inspector.results', {
85292                   n: results.collection.length,
85293                   search: value
85294                 });
85295               } else {
85296                 results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc);
85297                 messageText = _t('inspector.choose');
85298               }
85299
85300               list.call(drawList, results);
85301               message.html(messageText);
85302             }
85303
85304             var searchWrap = selection.append('div').attr('class', 'search-header');
85305             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
85306             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', inputevent);
85307
85308             if (_autofocus) {
85309               search.node().focus(); // Safari 14 doesn't always like to focus immediately,
85310               // so try again on the next pass
85311
85312               setTimeout(function () {
85313                 search.node().focus();
85314               }, 0);
85315             }
85316
85317             var listWrap = selection.append('div').attr('class', 'inspector-body');
85318             var list = listWrap.append('div').attr('class', 'preset-list').call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc));
85319             context.features().on('change.preset-list', updateForFeatureHiddenState);
85320           }
85321
85322           function drawList(list, presets) {
85323             presets = presets.matchAllGeometry(entityGeometries());
85324             var collection = presets.collection.reduce(function (collection, preset) {
85325               if (!preset) return collection;
85326
85327               if (preset.members) {
85328                 if (preset.members.collection.filter(function (preset) {
85329                   return preset.addable();
85330                 }).length > 1) {
85331                   collection.push(CategoryItem(preset));
85332                 }
85333               } else if (preset.addable()) {
85334                 collection.push(PresetItem(preset));
85335               }
85336
85337               return collection;
85338             }, []);
85339             var items = list.selectAll('.preset-list-item').data(collection, function (d) {
85340               return d.preset.id;
85341             });
85342             items.order();
85343             items.exit().remove();
85344             items.enter().append('div').attr('class', function (item) {
85345               return 'preset-list-item preset-' + item.preset.id.replace('/', '-');
85346             }).classed('current', function (item) {
85347               return _currentPresets.indexOf(item.preset) !== -1;
85348             }).each(function (item) {
85349               select(this).call(item);
85350             }).style('opacity', 0).transition().style('opacity', 1);
85351             updateForFeatureHiddenState();
85352           }
85353
85354           function itemKeydown(d3_event) {
85355             // the actively focused item
85356             var item = select(this.closest('.preset-list-item'));
85357             var parentItem = select(item.node().parentNode.closest('.preset-list-item')); // arrow down, move focus to the next, lower item
85358
85359             if (d3_event.keyCode === utilKeybinding.keyCodes['↓']) {
85360               d3_event.preventDefault();
85361               d3_event.stopPropagation(); // the next item in the list at the same level
85362
85363               var nextItem = select(item.node().nextElementSibling); // if there is no next item in this list
85364
85365               if (nextItem.empty()) {
85366                 // if there is a parent item
85367                 if (!parentItem.empty()) {
85368                   // the item is the last item of a sublist,
85369                   // select the next item at the parent level
85370                   nextItem = select(parentItem.node().nextElementSibling);
85371                 } // if the focused item is expanded
85372
85373               } else if (select(this).classed('expanded')) {
85374                 // select the first subitem instead
85375                 nextItem = item.select('.subgrid .preset-list-item:first-child');
85376               }
85377
85378               if (!nextItem.empty()) {
85379                 // focus on the next item
85380                 nextItem.select('.preset-list-button').node().focus();
85381               } // arrow up, move focus to the previous, higher item
85382
85383             } else if (d3_event.keyCode === utilKeybinding.keyCodes['↑']) {
85384               d3_event.preventDefault();
85385               d3_event.stopPropagation(); // the previous item in the list at the same level
85386
85387               var previousItem = select(item.node().previousElementSibling); // if there is no previous item in this list
85388
85389               if (previousItem.empty()) {
85390                 // if there is a parent item
85391                 if (!parentItem.empty()) {
85392                   // the item is the first subitem of a sublist select the parent item
85393                   previousItem = parentItem;
85394                 } // if the previous item is expanded
85395
85396               } else if (previousItem.select('.preset-list-button').classed('expanded')) {
85397                 // select the last subitem of the sublist of the previous item
85398                 previousItem = previousItem.select('.subgrid .preset-list-item:last-child');
85399               }
85400
85401               if (!previousItem.empty()) {
85402                 // focus on the previous item
85403                 previousItem.select('.preset-list-button').node().focus();
85404               } else {
85405                 // the focus is at the top of the list, move focus back to the search field
85406                 var search = select(this.closest('.preset-list-pane')).select('.preset-search-input');
85407                 search.node().focus();
85408               } // arrow left, move focus to the parent item if there is one
85409
85410             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
85411               d3_event.preventDefault();
85412               d3_event.stopPropagation(); // if there is a parent item, focus on the parent item
85413
85414               if (!parentItem.empty()) {
85415                 parentItem.select('.preset-list-button').node().focus();
85416               } // arrow right, choose this item
85417
85418             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
85419               d3_event.preventDefault();
85420               d3_event.stopPropagation();
85421               item.datum().choose.call(select(this).node());
85422             }
85423           }
85424
85425           function CategoryItem(preset) {
85426             var box,
85427                 sublist,
85428                 shown = false;
85429
85430             function item(selection) {
85431               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap category');
85432
85433               function click() {
85434                 var isExpanded = select(this).classed('expanded');
85435                 var iconName = isExpanded ? _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward' : '#iD-icon-down';
85436                 select(this).classed('expanded', !isExpanded);
85437                 select(this).selectAll('div.label-inner svg.icon use').attr('href', iconName);
85438                 item.choose();
85439               }
85440
85441               var geometries = entityGeometries();
85442               var button = wrap.append('button').attr('class', 'preset-list-button').classed('expanded', false).call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on('click', click).on('keydown', function (d3_event) {
85443                 // right arrow, expand the focused item
85444                 if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
85445                   d3_event.preventDefault();
85446                   d3_event.stopPropagation(); // if the item isn't expanded
85447
85448                   if (!select(this).classed('expanded')) {
85449                     // toggle expansion (expand the item)
85450                     click.call(this, d3_event);
85451                   } // left arrow, collapse the focused item
85452
85453                 } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
85454                   d3_event.preventDefault();
85455                   d3_event.stopPropagation(); // if the item is expanded
85456
85457                   if (select(this).classed('expanded')) {
85458                     // toggle expansion (collapse the item)
85459                     click.call(this, d3_event);
85460                   }
85461                 } else {
85462                   itemKeydown.call(this, d3_event);
85463                 }
85464               });
85465               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
85466               label.append('div').attr('class', 'namepart').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline')).append('span').html(function () {
85467                 return preset.nameLabel() + '&hellip;';
85468               });
85469               box = selection.append('div').attr('class', 'subgrid').style('max-height', '0px').style('opacity', 0);
85470               box.append('div').attr('class', 'arrow');
85471               sublist = box.append('div').attr('class', 'preset-list fillL3');
85472             }
85473
85474             item.choose = function () {
85475               if (!box || !sublist) return;
85476
85477               if (shown) {
85478                 shown = false;
85479                 box.transition().duration(200).style('opacity', '0').style('max-height', '0px').style('padding-bottom', '0px');
85480               } else {
85481                 shown = true;
85482                 var members = preset.members.matchAllGeometry(entityGeometries());
85483                 sublist.call(drawList, members);
85484                 box.transition().duration(200).style('opacity', '1').style('max-height', 200 + members.collection.length * 190 + 'px').style('padding-bottom', '10px');
85485               }
85486             };
85487
85488             item.preset = preset;
85489             return item;
85490           }
85491
85492           function PresetItem(preset) {
85493             function item(selection) {
85494               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap');
85495               var geometries = entityGeometries();
85496               var button = wrap.append('button').attr('class', 'preset-list-button').call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on('click', item.choose).on('keydown', itemKeydown);
85497               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
85498               var nameparts = [preset.nameLabel(), preset.subtitleLabel()].filter(Boolean);
85499               label.selectAll('.namepart').data(nameparts).enter().append('div').attr('class', 'namepart').html(function (d) {
85500                 return d;
85501               });
85502               wrap.call(item.reference.button);
85503               selection.call(item.reference.body);
85504             }
85505
85506             item.choose = function () {
85507               if (select(this).classed('disabled')) return;
85508
85509               if (!context.inIntro()) {
85510                 _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
85511               }
85512
85513               context.perform(function (graph) {
85514                 for (var i in _entityIDs) {
85515                   var entityID = _entityIDs[i];
85516                   var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
85517                   graph = actionChangePreset(entityID, oldPreset, preset)(graph);
85518                 }
85519
85520                 return graph;
85521               }, _t('operations.change_tags.annotation'));
85522               context.validator().validate(); // rerun validation
85523
85524               dispatch.call('choose', this, preset);
85525             };
85526
85527             item.help = function (d3_event) {
85528               d3_event.stopPropagation();
85529               item.reference.toggle();
85530             };
85531
85532             item.preset = preset;
85533             item.reference = uiTagReference(preset.reference());
85534             return item;
85535           }
85536
85537           function updateForFeatureHiddenState() {
85538             if (!_entityIDs.every(context.hasEntity)) return;
85539             var geometries = entityGeometries();
85540             var button = context.container().selectAll('.preset-list .preset-list-button'); // remove existing tooltips
85541
85542             button.call(uiTooltip().destroyAny);
85543             button.each(function (item, index) {
85544               var hiddenPresetFeaturesId;
85545
85546               for (var i in geometries) {
85547                 hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i]);
85548                 if (hiddenPresetFeaturesId) break;
85549               }
85550
85551               var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
85552               select(this).classed('disabled', isHiddenPreset);
85553
85554               if (isHiddenPreset) {
85555                 var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
85556                 select(this).call(uiTooltip().title(_t.html('inspector.hidden_preset.' + (isAutoHidden ? 'zoom' : 'manual'), {
85557                   features: _t.html('feature.' + hiddenPresetFeaturesId + '.description')
85558                 })).placement(index < 2 ? 'bottom' : 'top'));
85559               }
85560             });
85561           }
85562
85563           presetList.autofocus = function (val) {
85564             if (!arguments.length) return _autofocus;
85565             _autofocus = val;
85566             return presetList;
85567           };
85568
85569           presetList.entityIDs = function (val) {
85570             if (!arguments.length) return _entityIDs;
85571             _entityIDs = val;
85572             _currLoc = null;
85573
85574             if (_entityIDs && _entityIDs.length) {
85575               // calculate current location
85576               var extent = _entityIDs.reduce(function (extent, entityID) {
85577                 var entity = context.graph().entity(entityID);
85578                 return extent.extend(entity.extent(context.graph()));
85579               }, geoExtent());
85580
85581               _currLoc = extent.center(); // match presets
85582
85583               var presets = _entityIDs.map(function (entityID) {
85584                 return _mainPresetIndex.match(context.entity(entityID), context.graph());
85585               });
85586
85587               presetList.presets(presets);
85588             }
85589
85590             return presetList;
85591           };
85592
85593           presetList.presets = function (val) {
85594             if (!arguments.length) return _currentPresets;
85595             _currentPresets = val;
85596             return presetList;
85597           };
85598
85599           function entityGeometries() {
85600             var counts = {};
85601
85602             for (var i in _entityIDs) {
85603               var entityID = _entityIDs[i];
85604               var entity = context.entity(entityID);
85605               var geometry = entity.geometry(context.graph()); // Treat entities on addr:interpolation lines as points, not vertices (#3241)
85606
85607               if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
85608                 geometry = 'point';
85609               }
85610
85611               if (!counts[geometry]) counts[geometry] = 0;
85612               counts[geometry] += 1;
85613             }
85614
85615             return Object.keys(counts).sort(function (geom1, geom2) {
85616               return counts[geom2] - counts[geom1];
85617             });
85618           }
85619
85620           return utilRebind(presetList, dispatch, 'on');
85621         }
85622
85623         function uiViewOnOSM(context) {
85624           var _what; // an osmEntity or osmNote
85625
85626
85627           function viewOnOSM(selection) {
85628             var url;
85629
85630             if (_what instanceof osmEntity) {
85631               url = context.connection().entityURL(_what);
85632             } else if (_what instanceof osmNote) {
85633               url = context.connection().noteURL(_what);
85634             }
85635
85636             var data = !_what || _what.isNew() ? [] : [_what];
85637             var link = selection.selectAll('.view-on-osm').data(data, function (d) {
85638               return d.id;
85639             }); // exit
85640
85641             link.exit().remove(); // enter
85642
85643             var linkEnter = link.enter().append('a').attr('class', 'view-on-osm').attr('target', '_blank').attr('href', url).call(svgIcon('#iD-icon-out-link', 'inline'));
85644             linkEnter.append('span').html(_t.html('inspector.view_on_osm'));
85645           }
85646
85647           viewOnOSM.what = function (_) {
85648             if (!arguments.length) return _what;
85649             _what = _;
85650             return viewOnOSM;
85651           };
85652
85653           return viewOnOSM;
85654         }
85655
85656         function uiInspector(context) {
85657           var presetList = uiPresetList(context);
85658           var entityEditor = uiEntityEditor(context);
85659           var wrap = select(null),
85660               presetPane = select(null),
85661               editorPane = select(null);
85662           var _state = 'select';
85663
85664           var _entityIDs;
85665
85666           var _newFeature = false;
85667
85668           function inspector(selection) {
85669             presetList.entityIDs(_entityIDs).autofocus(_newFeature).on('choose', inspector.setPreset).on('cancel', function () {
85670               inspector.setPreset();
85671             });
85672             entityEditor.state(_state).entityIDs(_entityIDs).on('choose', inspector.showList);
85673             wrap = selection.selectAll('.panewrap').data([0]);
85674             var enter = wrap.enter().append('div').attr('class', 'panewrap');
85675             enter.append('div').attr('class', 'preset-list-pane pane');
85676             enter.append('div').attr('class', 'entity-editor-pane pane');
85677             wrap = wrap.merge(enter);
85678             presetPane = wrap.selectAll('.preset-list-pane');
85679             editorPane = wrap.selectAll('.entity-editor-pane');
85680
85681             function shouldDefaultToPresetList() {
85682               // always show the inspector on hover
85683               if (_state !== 'select') return false; // can only change preset on single selection
85684
85685               if (_entityIDs.length !== 1) return false;
85686               var entityID = _entityIDs[0];
85687               var entity = context.hasEntity(entityID);
85688               if (!entity) return false; // default to inspector if there are already tags
85689
85690               if (entity.hasNonGeometryTags()) return false; // prompt to select preset if feature is new and untagged
85691
85692               if (_newFeature) return true; // all existing features except vertices should default to inspector
85693
85694               if (entity.geometry(context.graph()) !== 'vertex') return false; // show vertex relations if any
85695
85696               if (context.graph().parentRelations(entity).length) return false; // show vertex issues if there are any
85697
85698               if (context.validator().getEntityIssues(entityID).length) return false; // show turn retriction editor for junction vertices
85699
85700               if (entity.isHighwayIntersection(context.graph())) return false; // otherwise show preset list for uninteresting vertices
85701
85702               return true;
85703             }
85704
85705             if (shouldDefaultToPresetList()) {
85706               wrap.style('right', '-100%');
85707               editorPane.classed('hide', true);
85708               presetPane.classed('hide', false).call(presetList);
85709             } else {
85710               wrap.style('right', '0%');
85711               presetPane.classed('hide', true);
85712               editorPane.classed('hide', false).call(entityEditor);
85713             }
85714
85715             var footer = selection.selectAll('.footer').data([0]);
85716             footer = footer.enter().append('div').attr('class', 'footer').merge(footer);
85717             footer.call(uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0])));
85718           }
85719
85720           inspector.showList = function (presets) {
85721             presetPane.classed('hide', false);
85722             wrap.transition().styleTween('right', function () {
85723               return interpolate$1('0%', '-100%');
85724             }).on('end', function () {
85725               editorPane.classed('hide', true);
85726             });
85727
85728             if (presets) {
85729               presetList.presets(presets);
85730             }
85731
85732             presetPane.call(presetList.autofocus(true));
85733           };
85734
85735           inspector.setPreset = function (preset) {
85736             // upon setting multipolygon, go to the area preset list instead of the editor
85737             if (preset && preset.id === 'type/multipolygon') {
85738               presetPane.call(presetList.autofocus(true));
85739             } else {
85740               editorPane.classed('hide', false);
85741               wrap.transition().styleTween('right', function () {
85742                 return interpolate$1('-100%', '0%');
85743               }).on('end', function () {
85744                 presetPane.classed('hide', true);
85745               });
85746
85747               if (preset) {
85748                 entityEditor.presets([preset]);
85749               }
85750
85751               editorPane.call(entityEditor);
85752             }
85753           };
85754
85755           inspector.state = function (val) {
85756             if (!arguments.length) return _state;
85757             _state = val;
85758             entityEditor.state(_state); // remove any old field help overlay that might have gotten attached to the inspector
85759
85760             context.container().selectAll('.field-help-body').remove();
85761             return inspector;
85762           };
85763
85764           inspector.entityIDs = function (val) {
85765             if (!arguments.length) return _entityIDs;
85766             _entityIDs = val;
85767             return inspector;
85768           };
85769
85770           inspector.newFeature = function (val) {
85771             if (!arguments.length) return _newFeature;
85772             _newFeature = val;
85773             return inspector;
85774           };
85775
85776           return inspector;
85777         }
85778
85779         function uiImproveOsmComments() {
85780           var _qaItem;
85781
85782           function issueComments(selection) {
85783             // make the div immediately so it appears above the buttons
85784             var comments = selection.selectAll('.comments-container').data([0]);
85785             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments); // must retrieve comments from API before they can be displayed
85786
85787             services.improveOSM.getComments(_qaItem).then(function (d) {
85788               if (!d.comments) return; // nothing to do here
85789
85790               var commentEnter = comments.selectAll('.comment').data(d.comments).enter().append('div').attr('class', 'comment');
85791               commentEnter.append('div').attr('class', 'comment-avatar').call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
85792               var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
85793               var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
85794               metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
85795                 var osm = services.osm;
85796                 var selection = select(this);
85797
85798                 if (osm && d.username) {
85799                   selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.username)).attr('target', '_blank');
85800                 }
85801
85802                 selection.html(function (d) {
85803                   return d.username;
85804                 });
85805               });
85806               metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
85807                 return _t.html('note.status.commented', {
85808                   when: localeDateString(d.timestamp)
85809                 });
85810               });
85811               mainEnter.append('div').attr('class', 'comment-text').append('p').html(function (d) {
85812                 return d.text;
85813               });
85814             })["catch"](function (err) {
85815               console.log(err); // eslint-disable-line no-console
85816             });
85817           }
85818
85819           function localeDateString(s) {
85820             if (!s) return null;
85821             var options = {
85822               day: 'numeric',
85823               month: 'short',
85824               year: 'numeric'
85825             };
85826             var d = new Date(s * 1000); // timestamp is served in seconds, date takes ms
85827
85828             if (isNaN(d.getTime())) return null;
85829             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
85830           }
85831
85832           issueComments.issue = function (val) {
85833             if (!arguments.length) return _qaItem;
85834             _qaItem = val;
85835             return issueComments;
85836           };
85837
85838           return issueComments;
85839         }
85840
85841         function uiImproveOsmDetails(context) {
85842           var _qaItem;
85843
85844           function issueDetail(d) {
85845             if (d.desc) return d.desc;
85846             var issueKey = d.issueKey;
85847             d.replacements = d.replacements || {};
85848             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
85849
85850             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".description"), d.replacements);
85851           }
85852
85853           function improveOsmDetails(selection) {
85854             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
85855               return "".concat(d.id, "-").concat(d.status || 0);
85856             });
85857             details.exit().remove();
85858             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
85859
85860             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85861             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
85862             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
85863
85864             var relatedEntities = [];
85865             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
85866               var link = select(this);
85867               var isObjectLink = link.classed('error_object_link');
85868               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
85869               var entity = context.hasEntity(entityID);
85870               relatedEntities.push(entityID); // Add click handler
85871
85872               link.on('mouseenter', function () {
85873                 utilHighlightEntities([entityID], true, context);
85874               }).on('mouseleave', function () {
85875                 utilHighlightEntities([entityID], false, context);
85876               }).on('click', function (d3_event) {
85877                 d3_event.preventDefault();
85878                 utilHighlightEntities([entityID], false, context);
85879                 var osmlayer = context.layers().layer('osm');
85880
85881                 if (!osmlayer.enabled()) {
85882                   osmlayer.enabled(true);
85883                 }
85884
85885                 context.map().centerZoom(_qaItem.loc, 20);
85886
85887                 if (entity) {
85888                   context.enter(modeSelect(context, [entityID]));
85889                 } else {
85890                   context.loadEntity(entityID, function (err, result) {
85891                     if (err) return;
85892                     var entity = result.data.find(function (e) {
85893                       return e.id === entityID;
85894                     });
85895                     if (entity) context.enter(modeSelect(context, [entityID]));
85896                   });
85897                 }
85898               }); // Replace with friendly name if possible
85899               // (The entity may not yet be loaded into the graph)
85900
85901               if (entity) {
85902                 var name = utilDisplayName(entity); // try to use common name
85903
85904                 if (!name && !isObjectLink) {
85905                   var preset = _mainPresetIndex.match(entity, context.graph());
85906                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
85907                 }
85908
85909                 if (name) {
85910                   this.innerText = name;
85911                 }
85912               }
85913             }); // Don't hide entities related to this error - #5880
85914
85915             context.features().forceVisible(relatedEntities);
85916             context.map().pan([0, 0]); // trigger a redraw
85917           }
85918
85919           improveOsmDetails.issue = function (val) {
85920             if (!arguments.length) return _qaItem;
85921             _qaItem = val;
85922             return improveOsmDetails;
85923           };
85924
85925           return improveOsmDetails;
85926         }
85927
85928         function uiImproveOsmHeader() {
85929           var _qaItem;
85930
85931           function issueTitle(d) {
85932             var issueKey = d.issueKey;
85933             d.replacements = d.replacements || {};
85934             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
85935
85936             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".title"), d.replacements);
85937           }
85938
85939           function improveOsmHeader(selection) {
85940             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
85941               return "".concat(d.id, "-").concat(d.status || 0);
85942             });
85943             header.exit().remove();
85944             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
85945             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
85946               return d.id < 0;
85947             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
85948               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
85949             });
85950             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');
85951             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
85952               var picon = d.icon;
85953
85954               if (!picon) {
85955                 return '';
85956               } else {
85957                 var isMaki = /^maki-/.test(picon);
85958                 return "#".concat(picon).concat(isMaki ? '-11' : '');
85959               }
85960             });
85961             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
85962           }
85963
85964           improveOsmHeader.issue = function (val) {
85965             if (!arguments.length) return _qaItem;
85966             _qaItem = val;
85967             return improveOsmHeader;
85968           };
85969
85970           return improveOsmHeader;
85971         }
85972
85973         function uiImproveOsmEditor(context) {
85974           var dispatch = dispatch$8('change');
85975           var qaDetails = uiImproveOsmDetails(context);
85976           var qaComments = uiImproveOsmComments();
85977           var qaHeader = uiImproveOsmHeader();
85978
85979           var _qaItem;
85980
85981           function improveOsmEditor(selection) {
85982             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
85983             headerEnter.append('button').attr('class', 'close').on('click', function () {
85984               return context.enter(modeBrowse(context));
85985             }).call(svgIcon('#iD-icon-close'));
85986             headerEnter.append('h3').html(_t.html('QA.improveOSM.title'));
85987             var body = selection.selectAll('.body').data([0]);
85988             body = body.enter().append('div').attr('class', 'body').merge(body);
85989             var editor = body.selectAll('.qa-editor').data([0]);
85990             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);
85991           }
85992
85993           function improveOsmSaveSection(selection) {
85994             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85995
85996             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
85997             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
85998               return "".concat(d.id, "-").concat(d.status || 0);
85999             }); // exit
86000
86001             saveSection.exit().remove(); // enter
86002
86003             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
86004             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('note.newComment'));
86005             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
86006               return d.newComment;
86007             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
86008
86009             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
86010
86011             function changeInput() {
86012               var input = select(this);
86013               var val = input.property('value').trim();
86014
86015               if (val === '') {
86016                 val = undefined;
86017               } // store the unsaved comment with the issue itself
86018
86019
86020               _qaItem = _qaItem.update({
86021                 newComment: val
86022               });
86023               var qaService = services.improveOSM;
86024
86025               if (qaService) {
86026                 qaService.replaceItem(_qaItem);
86027               }
86028
86029               saveSection.call(qaSaveButtons);
86030             }
86031           }
86032
86033           function qaSaveButtons(selection) {
86034             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
86035
86036             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
86037               return d.status + d.id;
86038             }); // exit
86039
86040             buttonSection.exit().remove(); // enter
86041
86042             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
86043             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
86044             buttonEnter.append('button').attr('class', 'button close-button action');
86045             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
86046
86047             buttonSection = buttonSection.merge(buttonEnter);
86048             buttonSection.select('.comment-button').attr('disabled', function (d) {
86049               return d.newComment ? null : true;
86050             }).on('click.comment', function (d3_event, d) {
86051               this.blur(); // avoid keeping focus on the button - #4641
86052
86053               var qaService = services.improveOSM;
86054
86055               if (qaService) {
86056                 qaService.postUpdate(d, function (err, item) {
86057                   return dispatch.call('change', item);
86058                 });
86059               }
86060             });
86061             buttonSection.select('.close-button').html(function (d) {
86062               var andComment = d.newComment ? '_comment' : '';
86063               return _t.html("QA.keepRight.close".concat(andComment));
86064             }).on('click.close', function (d3_event, d) {
86065               this.blur(); // avoid keeping focus on the button - #4641
86066
86067               var qaService = services.improveOSM;
86068
86069               if (qaService) {
86070                 d.newStatus = 'SOLVED';
86071                 qaService.postUpdate(d, function (err, item) {
86072                   return dispatch.call('change', item);
86073                 });
86074               }
86075             });
86076             buttonSection.select('.ignore-button').html(function (d) {
86077               var andComment = d.newComment ? '_comment' : '';
86078               return _t.html("QA.keepRight.ignore".concat(andComment));
86079             }).on('click.ignore', function (d3_event, d) {
86080               this.blur(); // avoid keeping focus on the button - #4641
86081
86082               var qaService = services.improveOSM;
86083
86084               if (qaService) {
86085                 d.newStatus = 'INVALID';
86086                 qaService.postUpdate(d, function (err, item) {
86087                   return dispatch.call('change', item);
86088                 });
86089               }
86090             });
86091           } // NOTE: Don't change method name until UI v3 is merged
86092
86093
86094           improveOsmEditor.error = function (val) {
86095             if (!arguments.length) return _qaItem;
86096             _qaItem = val;
86097             return improveOsmEditor;
86098           };
86099
86100           return utilRebind(improveOsmEditor, dispatch, 'on');
86101         }
86102
86103         function uiKeepRightDetails(context) {
86104           var _qaItem;
86105
86106           function issueDetail(d) {
86107             var itemType = d.itemType,
86108                 parentIssueType = d.parentIssueType;
86109             var unknown = _t.html('inspector.unknown');
86110             var replacements = d.replacements || {};
86111             replacements["default"] = unknown; // special key `default` works as a fallback string
86112
86113             var detail = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
86114
86115             if (detail === unknown) {
86116               detail = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
86117             }
86118
86119             return detail;
86120           }
86121
86122           function keepRightDetails(selection) {
86123             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
86124               return "".concat(d.id, "-").concat(d.status || 0);
86125             });
86126             details.exit().remove();
86127             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
86128
86129             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
86130             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
86131             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
86132
86133             var relatedEntities = [];
86134             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
86135               var link = select(this);
86136               var isObjectLink = link.classed('error_object_link');
86137               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
86138               var entity = context.hasEntity(entityID);
86139               relatedEntities.push(entityID); // Add click handler
86140
86141               link.on('mouseenter', function () {
86142                 utilHighlightEntities([entityID], true, context);
86143               }).on('mouseleave', function () {
86144                 utilHighlightEntities([entityID], false, context);
86145               }).on('click', function (d3_event) {
86146                 d3_event.preventDefault();
86147                 utilHighlightEntities([entityID], false, context);
86148                 var osmlayer = context.layers().layer('osm');
86149
86150                 if (!osmlayer.enabled()) {
86151                   osmlayer.enabled(true);
86152                 }
86153
86154                 context.map().centerZoomEase(_qaItem.loc, 20);
86155
86156                 if (entity) {
86157                   context.enter(modeSelect(context, [entityID]));
86158                 } else {
86159                   context.loadEntity(entityID, function (err, result) {
86160                     if (err) return;
86161                     var entity = result.data.find(function (e) {
86162                       return e.id === entityID;
86163                     });
86164                     if (entity) context.enter(modeSelect(context, [entityID]));
86165                   });
86166                 }
86167               }); // Replace with friendly name if possible
86168               // (The entity may not yet be loaded into the graph)
86169
86170               if (entity) {
86171                 var name = utilDisplayName(entity); // try to use common name
86172
86173                 if (!name && !isObjectLink) {
86174                   var preset = _mainPresetIndex.match(entity, context.graph());
86175                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
86176                 }
86177
86178                 if (name) {
86179                   this.innerText = name;
86180                 }
86181               }
86182             }); // Don't hide entities related to this issue - #5880
86183
86184             context.features().forceVisible(relatedEntities);
86185             context.map().pan([0, 0]); // trigger a redraw
86186           }
86187
86188           keepRightDetails.issue = function (val) {
86189             if (!arguments.length) return _qaItem;
86190             _qaItem = val;
86191             return keepRightDetails;
86192           };
86193
86194           return keepRightDetails;
86195         }
86196
86197         function uiKeepRightHeader() {
86198           var _qaItem;
86199
86200           function issueTitle(d) {
86201             var itemType = d.itemType,
86202                 parentIssueType = d.parentIssueType;
86203             var unknown = _t.html('inspector.unknown');
86204             var replacements = d.replacements || {};
86205             replacements["default"] = unknown; // special key `default` works as a fallback string
86206
86207             var title = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
86208
86209             if (title === unknown) {
86210               title = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
86211             }
86212
86213             return title;
86214           }
86215
86216           function keepRightHeader(selection) {
86217             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
86218               return "".concat(d.id, "-").concat(d.status || 0);
86219             });
86220             header.exit().remove();
86221             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
86222             var iconEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
86223               return d.id < 0;
86224             });
86225             iconEnter.append('div').attr('class', function (d) {
86226               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
86227             }).call(svgIcon('#iD-icon-bolt', 'qaItem-fill'));
86228             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
86229           }
86230
86231           keepRightHeader.issue = function (val) {
86232             if (!arguments.length) return _qaItem;
86233             _qaItem = val;
86234             return keepRightHeader;
86235           };
86236
86237           return keepRightHeader;
86238         }
86239
86240         function uiViewOnKeepRight() {
86241           var _qaItem;
86242
86243           function viewOnKeepRight(selection) {
86244             var url;
86245
86246             if (services.keepRight && _qaItem instanceof QAItem) {
86247               url = services.keepRight.issueURL(_qaItem);
86248             }
86249
86250             var link = selection.selectAll('.view-on-keepRight').data(url ? [url] : []); // exit
86251
86252             link.exit().remove(); // enter
86253
86254             var linkEnter = link.enter().append('a').attr('class', 'view-on-keepRight').attr('target', '_blank').attr('rel', 'noopener') // security measure
86255             .attr('href', function (d) {
86256               return d;
86257             }).call(svgIcon('#iD-icon-out-link', 'inline'));
86258             linkEnter.append('span').html(_t.html('inspector.view_on_keepRight'));
86259           }
86260
86261           viewOnKeepRight.what = function (val) {
86262             if (!arguments.length) return _qaItem;
86263             _qaItem = val;
86264             return viewOnKeepRight;
86265           };
86266
86267           return viewOnKeepRight;
86268         }
86269
86270         function uiKeepRightEditor(context) {
86271           var dispatch = dispatch$8('change');
86272           var qaDetails = uiKeepRightDetails(context);
86273           var qaHeader = uiKeepRightHeader();
86274
86275           var _qaItem;
86276
86277           function keepRightEditor(selection) {
86278             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
86279             headerEnter.append('button').attr('class', 'close').on('click', function () {
86280               return context.enter(modeBrowse(context));
86281             }).call(svgIcon('#iD-icon-close'));
86282             headerEnter.append('h3').html(_t.html('QA.keepRight.title'));
86283             var body = selection.selectAll('.body').data([0]);
86284             body = body.enter().append('div').attr('class', 'body').merge(body);
86285             var editor = body.selectAll('.qa-editor').data([0]);
86286             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
86287             var footer = selection.selectAll('.footer').data([0]);
86288             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnKeepRight().what(_qaItem));
86289           }
86290
86291           function keepRightSaveSection(selection) {
86292             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
86293
86294             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
86295             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
86296               return "".concat(d.id, "-").concat(d.status || 0);
86297             }); // exit
86298
86299             saveSection.exit().remove(); // enter
86300
86301             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
86302             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('QA.keepRight.comment'));
86303             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
86304               return d.newComment || d.comment;
86305             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
86306
86307             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
86308
86309             function changeInput() {
86310               var input = select(this);
86311               var val = input.property('value').trim();
86312
86313               if (val === _qaItem.comment) {
86314                 val = undefined;
86315               } // store the unsaved comment with the issue itself
86316
86317
86318               _qaItem = _qaItem.update({
86319                 newComment: val
86320               });
86321               var qaService = services.keepRight;
86322
86323               if (qaService) {
86324                 qaService.replaceItem(_qaItem); // update keepright cache
86325               }
86326
86327               saveSection.call(qaSaveButtons);
86328             }
86329           }
86330
86331           function qaSaveButtons(selection) {
86332             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
86333
86334             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
86335               return d.status + d.id;
86336             }); // exit
86337
86338             buttonSection.exit().remove(); // enter
86339
86340             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
86341             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
86342             buttonEnter.append('button').attr('class', 'button close-button action');
86343             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
86344
86345             buttonSection = buttonSection.merge(buttonEnter);
86346             buttonSection.select('.comment-button') // select and propagate data
86347             .attr('disabled', function (d) {
86348               return d.newComment ? null : true;
86349             }).on('click.comment', function (d3_event, d) {
86350               this.blur(); // avoid keeping focus on the button - #4641
86351
86352               var qaService = services.keepRight;
86353
86354               if (qaService) {
86355                 qaService.postUpdate(d, function (err, item) {
86356                   return dispatch.call('change', item);
86357                 });
86358               }
86359             });
86360             buttonSection.select('.close-button') // select and propagate data
86361             .html(function (d) {
86362               var andComment = d.newComment ? '_comment' : '';
86363               return _t.html("QA.keepRight.close".concat(andComment));
86364             }).on('click.close', function (d3_event, d) {
86365               this.blur(); // avoid keeping focus on the button - #4641
86366
86367               var qaService = services.keepRight;
86368
86369               if (qaService) {
86370                 d.newStatus = 'ignore_t'; // ignore temporarily (item fixed)
86371
86372                 qaService.postUpdate(d, function (err, item) {
86373                   return dispatch.call('change', item);
86374                 });
86375               }
86376             });
86377             buttonSection.select('.ignore-button') // select and propagate data
86378             .html(function (d) {
86379               var andComment = d.newComment ? '_comment' : '';
86380               return _t.html("QA.keepRight.ignore".concat(andComment));
86381             }).on('click.ignore', function (d3_event, d) {
86382               this.blur(); // avoid keeping focus on the button - #4641
86383
86384               var qaService = services.keepRight;
86385
86386               if (qaService) {
86387                 d.newStatus = 'ignore'; // ignore permanently (false positive)
86388
86389                 qaService.postUpdate(d, function (err, item) {
86390                   return dispatch.call('change', item);
86391                 });
86392               }
86393             });
86394           } // NOTE: Don't change method name until UI v3 is merged
86395
86396
86397           keepRightEditor.error = function (val) {
86398             if (!arguments.length) return _qaItem;
86399             _qaItem = val;
86400             return keepRightEditor;
86401           };
86402
86403           return utilRebind(keepRightEditor, dispatch, 'on');
86404         }
86405
86406         function uiOsmoseDetails(context) {
86407           var _qaItem;
86408
86409           function issueString(d, type) {
86410             if (!d) return ''; // Issue strings are cached from Osmose API
86411
86412             var s = services.osmose.getStrings(d.itemType);
86413             return type in s ? s[type] : '';
86414           }
86415
86416           function osmoseDetails(selection) {
86417             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
86418               return "".concat(d.id, "-").concat(d.status || 0);
86419             });
86420             details.exit().remove();
86421             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // Description
86422
86423             if (issueString(_qaItem, 'detail')) {
86424               var div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
86425               div.append('h4').html(_t.html('QA.keepRight.detail_description'));
86426               div.append('p').attr('class', 'qa-details-description-text').html(function (d) {
86427                 return issueString(d, 'detail');
86428               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
86429             } // Elements (populated later as data is requested)
86430
86431
86432             var detailsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection');
86433             var elemsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection'); // Suggested Fix (mustn't exist for every issue type)
86434
86435             if (issueString(_qaItem, 'fix')) {
86436               var _div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
86437
86438               _div.append('h4').html(_t.html('QA.osmose.fix_title'));
86439
86440               _div.append('p').html(function (d) {
86441                 return issueString(d, 'fix');
86442               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
86443             } // Common Pitfalls (mustn't exist for every issue type)
86444
86445
86446             if (issueString(_qaItem, 'trap')) {
86447               var _div2 = detailsEnter.append('div').attr('class', 'qa-details-subsection');
86448
86449               _div2.append('h4').html(_t.html('QA.osmose.trap_title'));
86450
86451               _div2.append('p').html(function (d) {
86452                 return issueString(d, 'trap');
86453               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
86454             } // Save current item to check if UI changed by time request resolves
86455
86456
86457             var thisItem = _qaItem;
86458             services.osmose.loadIssueDetail(_qaItem).then(function (d) {
86459               // No details to add if there are no associated issue elements
86460               if (!d.elems || d.elems.length === 0) return; // Do nothing if UI has moved on by the time this resolves
86461
86462               if (context.selectedErrorID() !== thisItem.id && context.container().selectAll(".qaItem.osmose.hover.itemId-".concat(thisItem.id)).empty()) return; // Things like keys and values are dynamically added to a subtitle string
86463
86464               if (d.detail) {
86465                 detailsDiv.append('h4').html(_t.html('QA.osmose.detail_title'));
86466                 detailsDiv.append('p').html(function (d) {
86467                   return d.detail;
86468                 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
86469               } // Create list of linked issue elements
86470
86471
86472               elemsDiv.append('h4').html(_t.html('QA.osmose.elems_title'));
86473               elemsDiv.append('ul').selectAll('li').data(d.elems).enter().append('li').append('a').attr('href', '#').attr('class', 'error_entity_link').html(function (d) {
86474                 return d;
86475               }).each(function () {
86476                 var link = select(this);
86477                 var entityID = this.textContent;
86478                 var entity = context.hasEntity(entityID); // Add click handler
86479
86480                 link.on('mouseenter', function () {
86481                   utilHighlightEntities([entityID], true, context);
86482                 }).on('mouseleave', function () {
86483                   utilHighlightEntities([entityID], false, context);
86484                 }).on('click', function (d3_event) {
86485                   d3_event.preventDefault();
86486                   utilHighlightEntities([entityID], false, context);
86487                   var osmlayer = context.layers().layer('osm');
86488
86489                   if (!osmlayer.enabled()) {
86490                     osmlayer.enabled(true);
86491                   }
86492
86493                   context.map().centerZoom(d.loc, 20);
86494
86495                   if (entity) {
86496                     context.enter(modeSelect(context, [entityID]));
86497                   } else {
86498                     context.loadEntity(entityID, function (err, result) {
86499                       if (err) return;
86500                       var entity = result.data.find(function (e) {
86501                         return e.id === entityID;
86502                       });
86503                       if (entity) context.enter(modeSelect(context, [entityID]));
86504                     });
86505                   }
86506                 }); // Replace with friendly name if possible
86507                 // (The entity may not yet be loaded into the graph)
86508
86509                 if (entity) {
86510                   var name = utilDisplayName(entity); // try to use common name
86511
86512                   if (!name) {
86513                     var preset = _mainPresetIndex.match(entity, context.graph());
86514                     name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
86515                   }
86516
86517                   if (name) {
86518                     this.innerText = name;
86519                   }
86520                 }
86521               }); // Don't hide entities related to this issue - #5880
86522
86523               context.features().forceVisible(d.elems);
86524               context.map().pan([0, 0]); // trigger a redraw
86525             })["catch"](function (err) {
86526               console.log(err); // eslint-disable-line no-console
86527             });
86528           }
86529
86530           osmoseDetails.issue = function (val) {
86531             if (!arguments.length) return _qaItem;
86532             _qaItem = val;
86533             return osmoseDetails;
86534           };
86535
86536           return osmoseDetails;
86537         }
86538
86539         function uiOsmoseHeader() {
86540           var _qaItem;
86541
86542           function issueTitle(d) {
86543             var unknown = _t('inspector.unknown');
86544             if (!d) return unknown; // Issue titles supplied by Osmose
86545
86546             var s = services.osmose.getStrings(d.itemType);
86547             return 'title' in s ? s.title : unknown;
86548           }
86549
86550           function osmoseHeader(selection) {
86551             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
86552               return "".concat(d.id, "-").concat(d.status || 0);
86553             });
86554             header.exit().remove();
86555             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
86556             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
86557               return d.id < 0;
86558             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
86559               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
86560             });
86561             svgEnter.append('polygon').attr('fill', function (d) {
86562               return services.osmose.getColor(d.item);
86563             }).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');
86564             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
86565               var picon = d.icon;
86566
86567               if (!picon) {
86568                 return '';
86569               } else {
86570                 var isMaki = /^maki-/.test(picon);
86571                 return "#".concat(picon).concat(isMaki ? '-11' : '');
86572               }
86573             });
86574             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
86575           }
86576
86577           osmoseHeader.issue = function (val) {
86578             if (!arguments.length) return _qaItem;
86579             _qaItem = val;
86580             return osmoseHeader;
86581           };
86582
86583           return osmoseHeader;
86584         }
86585
86586         function uiViewOnOsmose() {
86587           var _qaItem;
86588
86589           function viewOnOsmose(selection) {
86590             var url;
86591
86592             if (services.osmose && _qaItem instanceof QAItem) {
86593               url = services.osmose.itemURL(_qaItem);
86594             }
86595
86596             var link = selection.selectAll('.view-on-osmose').data(url ? [url] : []); // exit
86597
86598             link.exit().remove(); // enter
86599
86600             var linkEnter = link.enter().append('a').attr('class', 'view-on-osmose').attr('target', '_blank').attr('rel', 'noopener') // security measure
86601             .attr('href', function (d) {
86602               return d;
86603             }).call(svgIcon('#iD-icon-out-link', 'inline'));
86604             linkEnter.append('span').html(_t.html('inspector.view_on_osmose'));
86605           }
86606
86607           viewOnOsmose.what = function (val) {
86608             if (!arguments.length) return _qaItem;
86609             _qaItem = val;
86610             return viewOnOsmose;
86611           };
86612
86613           return viewOnOsmose;
86614         }
86615
86616         function uiOsmoseEditor(context) {
86617           var dispatch = dispatch$8('change');
86618           var qaDetails = uiOsmoseDetails(context);
86619           var qaHeader = uiOsmoseHeader();
86620
86621           var _qaItem;
86622
86623           function osmoseEditor(selection) {
86624             var header = selection.selectAll('.header').data([0]);
86625             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
86626             headerEnter.append('button').attr('class', 'close').on('click', function () {
86627               return context.enter(modeBrowse(context));
86628             }).call(svgIcon('#iD-icon-close'));
86629             headerEnter.append('h3').html(_t.html('QA.osmose.title'));
86630             var body = selection.selectAll('.body').data([0]);
86631             body = body.enter().append('div').attr('class', 'body').merge(body);
86632             var editor = body.selectAll('.qa-editor').data([0]);
86633             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
86634             var footer = selection.selectAll('.footer').data([0]);
86635             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnOsmose().what(_qaItem));
86636           }
86637
86638           function osmoseSaveSection(selection) {
86639             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
86640
86641             var isShown = _qaItem && isSelected;
86642             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
86643               return "".concat(d.id, "-").concat(d.status || 0);
86644             }); // exit
86645
86646             saveSection.exit().remove(); // enter
86647
86648             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf'); // update
86649
86650             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
86651           }
86652
86653           function qaSaveButtons(selection) {
86654             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
86655
86656             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
86657               return d.status + d.id;
86658             }); // exit
86659
86660             buttonSection.exit().remove(); // enter
86661
86662             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
86663             buttonEnter.append('button').attr('class', 'button close-button action');
86664             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
86665
86666             buttonSection = buttonSection.merge(buttonEnter);
86667             buttonSection.select('.close-button').html(_t.html('QA.keepRight.close')).on('click.close', function (d3_event, d) {
86668               this.blur(); // avoid keeping focus on the button - #4641
86669
86670               var qaService = services.osmose;
86671
86672               if (qaService) {
86673                 d.newStatus = 'done';
86674                 qaService.postUpdate(d, function (err, item) {
86675                   return dispatch.call('change', item);
86676                 });
86677               }
86678             });
86679             buttonSection.select('.ignore-button').html(_t.html('QA.keepRight.ignore')).on('click.ignore', function (d3_event, d) {
86680               this.blur(); // avoid keeping focus on the button - #4641
86681
86682               var qaService = services.osmose;
86683
86684               if (qaService) {
86685                 d.newStatus = 'false';
86686                 qaService.postUpdate(d, function (err, item) {
86687                   return dispatch.call('change', item);
86688                 });
86689               }
86690             });
86691           } // NOTE: Don't change method name until UI v3 is merged
86692
86693
86694           osmoseEditor.error = function (val) {
86695             if (!arguments.length) return _qaItem;
86696             _qaItem = val;
86697             return osmoseEditor;
86698           };
86699
86700           return utilRebind(osmoseEditor, dispatch, 'on');
86701         }
86702
86703         function uiNoteComments() {
86704           var _note;
86705
86706           function noteComments(selection) {
86707             if (_note.isNew()) return; // don't draw .comments-container
86708
86709             var comments = selection.selectAll('.comments-container').data([0]);
86710             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments);
86711             var commentEnter = comments.selectAll('.comment').data(_note.comments).enter().append('div').attr('class', 'comment');
86712             commentEnter.append('div').attr('class', function (d) {
86713               return 'comment-avatar user-' + d.uid;
86714             }).call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
86715             var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
86716             var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
86717             metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
86718               var selection = select(this);
86719               var osm = services.osm;
86720
86721               if (osm && d.user) {
86722                 selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.user)).attr('target', '_blank');
86723               }
86724
86725               selection.html(function (d) {
86726                 return d.user || _t.html('note.anonymous');
86727               });
86728             });
86729             metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
86730               return _t('note.status.' + d.action, {
86731                 when: localeDateString(d.date)
86732               });
86733             });
86734             mainEnter.append('div').attr('class', 'comment-text').html(function (d) {
86735               return d.html;
86736             }).selectAll('a').attr('rel', 'noopener nofollow').attr('target', '_blank');
86737             comments.call(replaceAvatars);
86738           }
86739
86740           function replaceAvatars(selection) {
86741             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
86742             var osm = services.osm;
86743             if (showThirdPartyIcons !== 'true' || !osm) return;
86744             var uids = {}; // gather uids in the comment thread
86745
86746             _note.comments.forEach(function (d) {
86747               if (d.uid) uids[d.uid] = true;
86748             });
86749
86750             Object.keys(uids).forEach(function (uid) {
86751               osm.loadUser(uid, function (err, user) {
86752                 if (!user || !user.image_url) return;
86753                 selection.selectAll('.comment-avatar.user-' + uid).html('').append('img').attr('class', 'icon comment-avatar-icon').attr('src', user.image_url).attr('alt', user.display_name);
86754               });
86755             });
86756           }
86757
86758           function localeDateString(s) {
86759             if (!s) return null;
86760             var options = {
86761               day: 'numeric',
86762               month: 'short',
86763               year: 'numeric'
86764             };
86765             s = s.replace(/-/g, '/'); // fix browser-specific Date() issues
86766
86767             var d = new Date(s);
86768             if (isNaN(d.getTime())) return null;
86769             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
86770           }
86771
86772           noteComments.note = function (val) {
86773             if (!arguments.length) return _note;
86774             _note = val;
86775             return noteComments;
86776           };
86777
86778           return noteComments;
86779         }
86780
86781         function uiNoteHeader() {
86782           var _note;
86783
86784           function noteHeader(selection) {
86785             var header = selection.selectAll('.note-header').data(_note ? [_note] : [], function (d) {
86786               return d.status + d.id;
86787             });
86788             header.exit().remove();
86789             var headerEnter = header.enter().append('div').attr('class', 'note-header');
86790             var iconEnter = headerEnter.append('div').attr('class', function (d) {
86791               return 'note-header-icon ' + d.status;
86792             }).classed('new', function (d) {
86793               return d.id < 0;
86794             });
86795             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-note', 'note-fill'));
86796             iconEnter.each(function (d) {
86797               var statusIcon;
86798
86799               if (d.id < 0) {
86800                 statusIcon = '#iD-icon-plus';
86801               } else if (d.status === 'open') {
86802                 statusIcon = '#iD-icon-close';
86803               } else {
86804                 statusIcon = '#iD-icon-apply';
86805               }
86806
86807               iconEnter.append('div').attr('class', 'note-icon-annotation').call(svgIcon(statusIcon, 'icon-annotation'));
86808             });
86809             headerEnter.append('div').attr('class', 'note-header-label').html(function (d) {
86810               if (_note.isNew()) {
86811                 return _t('note.new');
86812               }
86813
86814               return _t('note.note') + ' ' + d.id + ' ' + (d.status === 'closed' ? _t('note.closed') : '');
86815             });
86816           }
86817
86818           noteHeader.note = function (val) {
86819             if (!arguments.length) return _note;
86820             _note = val;
86821             return noteHeader;
86822           };
86823
86824           return noteHeader;
86825         }
86826
86827         function uiNoteReport() {
86828           var _note;
86829
86830           function noteReport(selection) {
86831             var url;
86832
86833             if (services.osm && _note instanceof osmNote && !_note.isNew()) {
86834               url = services.osm.noteReportURL(_note);
86835             }
86836
86837             var link = selection.selectAll('.note-report').data(url ? [url] : []); // exit
86838
86839             link.exit().remove(); // enter
86840
86841             var linkEnter = link.enter().append('a').attr('class', 'note-report').attr('target', '_blank').attr('href', function (d) {
86842               return d;
86843             }).call(svgIcon('#iD-icon-out-link', 'inline'));
86844             linkEnter.append('span').html(_t.html('note.report'));
86845           }
86846
86847           noteReport.note = function (val) {
86848             if (!arguments.length) return _note;
86849             _note = val;
86850             return noteReport;
86851           };
86852
86853           return noteReport;
86854         }
86855
86856         function uiNoteEditor(context) {
86857           var dispatch = dispatch$8('change');
86858           var noteComments = uiNoteComments();
86859           var noteHeader = uiNoteHeader(); // var formFields = uiFormFields(context);
86860
86861           var _note;
86862
86863           var _newNote; // var _fieldsArr;
86864
86865
86866           function noteEditor(selection) {
86867             var header = selection.selectAll('.header').data([0]);
86868             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
86869             headerEnter.append('button').attr('class', 'close').on('click', function () {
86870               context.enter(modeBrowse(context));
86871             }).call(svgIcon('#iD-icon-close'));
86872             headerEnter.append('h3').html(_t.html('note.title'));
86873             var body = selection.selectAll('.body').data([0]);
86874             body = body.enter().append('div').attr('class', 'body').merge(body);
86875             var editor = body.selectAll('.note-editor').data([0]);
86876             editor.enter().append('div').attr('class', 'modal-section note-editor').merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
86877             var footer = selection.selectAll('.footer').data([0]);
86878             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnOSM(context).what(_note)).call(uiNoteReport().note(_note)); // rerender the note editor on any auth change
86879
86880             var osm = services.osm;
86881
86882             if (osm) {
86883               osm.on('change.note-save', function () {
86884                 selection.call(noteEditor);
86885               });
86886             }
86887           }
86888
86889           function noteSaveSection(selection) {
86890             var isSelected = _note && _note.id === context.selectedNoteID();
86891
86892             var noteSave = selection.selectAll('.note-save').data(isSelected ? [_note] : [], function (d) {
86893               return d.status + d.id;
86894             }); // exit
86895
86896             noteSave.exit().remove(); // enter
86897
86898             var noteSaveEnter = noteSave.enter().append('div').attr('class', 'note-save save-section cf'); // // if new note, show categories to pick from
86899             // if (_note.isNew()) {
86900             //     var presets = presetManager;
86901             //     // NOTE: this key isn't a age and therefore there is no documentation (yet)
86902             //     _fieldsArr = [
86903             //         uiField(context, presets.field('category'), null, { show: true, revert: false }),
86904             //     ];
86905             //     _fieldsArr.forEach(function(field) {
86906             //         field
86907             //             .on('change', changeCategory);
86908             //     });
86909             //     noteSaveEnter
86910             //         .append('div')
86911             //         .attr('class', 'note-category')
86912             //         .call(formFields.fieldsArr(_fieldsArr));
86913             // }
86914             // function changeCategory() {
86915             //     // NOTE: perhaps there is a better way to get value
86916             //     var val = context.container().select('input[name=\'category\']:checked').property('__data__') || undefined;
86917             //     // store the unsaved category with the note itself
86918             //     _note = _note.update({ newCategory: val });
86919             //     var osm = services.osm;
86920             //     if (osm) {
86921             //         osm.replaceNote(_note);  // update note cache
86922             //     }
86923             //     noteSave
86924             //         .call(noteSaveButtons);
86925             // }
86926
86927             noteSaveEnter.append('h4').attr('class', '.note-save-header').html(function () {
86928               return _note.isNew() ? _t('note.newDescription') : _t('note.newComment');
86929             });
86930             var commentTextarea = noteSaveEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('note.inputPlaceholder')).attr('maxlength', 1000).property('value', function (d) {
86931               return d.newComment;
86932             }).call(utilNoAuto).on('keydown.note-input', keydown).on('input.note-input', changeInput).on('blur.note-input', changeInput);
86933
86934             if (!commentTextarea.empty() && _newNote) {
86935               // autofocus the comment field for new notes
86936               commentTextarea.node().focus();
86937             } // update
86938
86939
86940             noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons); // fast submit if user presses cmd+enter
86941
86942             function keydown(d3_event) {
86943               if (!(d3_event.keyCode === 13 && // ↩ Return
86944               d3_event.metaKey)) return;
86945               var osm = services.osm;
86946               if (!osm) return;
86947               var hasAuth = osm.authenticated();
86948               if (!hasAuth) return;
86949               if (!_note.newComment) return;
86950               d3_event.preventDefault();
86951               select(this).on('keydown.note-input', null); // focus on button and submit
86952
86953               window.setTimeout(function () {
86954                 if (_note.isNew()) {
86955                   noteSave.selectAll('.save-button').node().focus();
86956                   clickSave();
86957                 } else {
86958                   noteSave.selectAll('.comment-button').node().focus();
86959                   clickComment();
86960                 }
86961               }, 10);
86962             }
86963
86964             function changeInput() {
86965               var input = select(this);
86966               var val = input.property('value').trim() || undefined; // store the unsaved comment with the note itself
86967
86968               _note = _note.update({
86969                 newComment: val
86970               });
86971               var osm = services.osm;
86972
86973               if (osm) {
86974                 osm.replaceNote(_note); // update note cache
86975               }
86976
86977               noteSave.call(noteSaveButtons);
86978             }
86979           }
86980
86981           function userDetails(selection) {
86982             var detailSection = selection.selectAll('.detail-section').data([0]);
86983             detailSection = detailSection.enter().append('div').attr('class', 'detail-section').merge(detailSection);
86984             var osm = services.osm;
86985             if (!osm) return; // Add warning if user is not logged in
86986
86987             var hasAuth = osm.authenticated();
86988             var authWarning = detailSection.selectAll('.auth-warning').data(hasAuth ? [] : [0]);
86989             authWarning.exit().transition().duration(200).style('opacity', 0).remove();
86990             var authEnter = authWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning auth-warning').style('opacity', 0);
86991             authEnter.call(svgIcon('#iD-icon-alert', 'inline'));
86992             authEnter.append('span').html(_t.html('note.login'));
86993             authEnter.append('a').attr('target', '_blank').call(svgIcon('#iD-icon-out-link', 'inline')).append('span').html(_t.html('login')).on('click.note-login', function (d3_event) {
86994               d3_event.preventDefault();
86995               osm.authenticate();
86996             });
86997             authEnter.transition().duration(200).style('opacity', 1);
86998             var prose = detailSection.selectAll('.note-save-prose').data(hasAuth ? [0] : []);
86999             prose.exit().remove();
87000             prose = prose.enter().append('p').attr('class', 'note-save-prose').html(_t.html('note.upload_explanation')).merge(prose);
87001             osm.userDetails(function (err, user) {
87002               if (err) return;
87003               var userLink = select(document.createElement('div'));
87004
87005               if (user.image_url) {
87006                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
87007               }
87008
87009               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
87010               prose.html(_t.html('note.upload_explanation_with_user', {
87011                 user: userLink.html()
87012               }));
87013             });
87014           }
87015
87016           function noteSaveButtons(selection) {
87017             var osm = services.osm;
87018             var hasAuth = osm && osm.authenticated();
87019
87020             var isSelected = _note && _note.id === context.selectedNoteID();
87021
87022             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_note] : [], function (d) {
87023               return d.status + d.id;
87024             }); // exit
87025
87026             buttonSection.exit().remove(); // enter
87027
87028             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
87029
87030             if (_note.isNew()) {
87031               buttonEnter.append('button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
87032               buttonEnter.append('button').attr('class', 'button save-button action').html(_t.html('note.save'));
87033             } else {
87034               buttonEnter.append('button').attr('class', 'button status-button action');
87035               buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('note.comment'));
87036             } // update
87037
87038
87039             buttonSection = buttonSection.merge(buttonEnter);
87040             buttonSection.select('.cancel-button') // select and propagate data
87041             .on('click.cancel', clickCancel);
87042             buttonSection.select('.save-button') // select and propagate data
87043             .attr('disabled', isSaveDisabled).on('click.save', clickSave);
87044             buttonSection.select('.status-button') // select and propagate data
87045             .attr('disabled', hasAuth ? null : true).html(function (d) {
87046               var action = d.status === 'open' ? 'close' : 'open';
87047               var andComment = d.newComment ? '_comment' : '';
87048               return _t('note.' + action + andComment);
87049             }).on('click.status', clickStatus);
87050             buttonSection.select('.comment-button') // select and propagate data
87051             .attr('disabled', isSaveDisabled).on('click.comment', clickComment);
87052
87053             function isSaveDisabled(d) {
87054               return hasAuth && d.status === 'open' && d.newComment ? null : true;
87055             }
87056           }
87057
87058           function clickCancel(d3_event, d) {
87059             this.blur(); // avoid keeping focus on the button - #4641
87060
87061             var osm = services.osm;
87062
87063             if (osm) {
87064               osm.removeNote(d);
87065             }
87066
87067             context.enter(modeBrowse(context));
87068             dispatch.call('change');
87069           }
87070
87071           function clickSave(d3_event, d) {
87072             this.blur(); // avoid keeping focus on the button - #4641
87073
87074             var osm = services.osm;
87075
87076             if (osm) {
87077               osm.postNoteCreate(d, function (err, note) {
87078                 dispatch.call('change', note);
87079               });
87080             }
87081           }
87082
87083           function clickStatus(d3_event, d) {
87084             this.blur(); // avoid keeping focus on the button - #4641
87085
87086             var osm = services.osm;
87087
87088             if (osm) {
87089               var setStatus = d.status === 'open' ? 'closed' : 'open';
87090               osm.postNoteUpdate(d, setStatus, function (err, note) {
87091                 dispatch.call('change', note);
87092               });
87093             }
87094           }
87095
87096           function clickComment(d3_event, d) {
87097             this.blur(); // avoid keeping focus on the button - #4641
87098
87099             var osm = services.osm;
87100
87101             if (osm) {
87102               osm.postNoteUpdate(d, d.status, function (err, note) {
87103                 dispatch.call('change', note);
87104               });
87105             }
87106           }
87107
87108           noteEditor.note = function (val) {
87109             if (!arguments.length) return _note;
87110             _note = val;
87111             return noteEditor;
87112           };
87113
87114           noteEditor.newNote = function (val) {
87115             if (!arguments.length) return _newNote;
87116             _newNote = val;
87117             return noteEditor;
87118           };
87119
87120           return utilRebind(noteEditor, dispatch, 'on');
87121         }
87122
87123         function uiSidebar(context) {
87124           var inspector = uiInspector(context);
87125           var dataEditor = uiDataEditor(context);
87126           var noteEditor = uiNoteEditor(context);
87127           var improveOsmEditor = uiImproveOsmEditor(context);
87128           var keepRightEditor = uiKeepRightEditor(context);
87129           var osmoseEditor = uiOsmoseEditor(context);
87130
87131           var _current;
87132
87133           var _wasData = false;
87134           var _wasNote = false;
87135           var _wasQaItem = false; // use pointer events on supported platforms; fallback to mouse events
87136
87137           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
87138
87139           function sidebar(selection) {
87140             var container = context.container();
87141             var minWidth = 240;
87142             var sidebarWidth;
87143             var containerWidth;
87144             var dragOffset; // Set the initial width constraints
87145
87146             selection.style('min-width', minWidth + 'px').style('max-width', '400px').style('width', '33.3333%');
87147             var resizer = selection.append('div').attr('class', 'sidebar-resizer').on(_pointerPrefix + 'down.sidebar-resizer', pointerdown);
87148             var downPointerId, lastClientX, containerLocGetter;
87149
87150             function pointerdown(d3_event) {
87151               if (downPointerId) return;
87152               if ('button' in d3_event && d3_event.button !== 0) return;
87153               downPointerId = d3_event.pointerId || 'mouse';
87154               lastClientX = d3_event.clientX;
87155               containerLocGetter = utilFastMouse(container.node()); // offset from edge of sidebar-resizer
87156
87157               dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
87158               sidebarWidth = selection.node().getBoundingClientRect().width;
87159               containerWidth = container.node().getBoundingClientRect().width;
87160               var widthPct = sidebarWidth / containerWidth * 100;
87161               selection.style('width', widthPct + '%') // lock in current width
87162               .style('max-width', '85%'); // but allow larger widths
87163
87164               resizer.classed('dragging', true);
87165               select(window).on('touchmove.sidebar-resizer', function (d3_event) {
87166                 // disable page scrolling while resizing on touch input
87167                 d3_event.preventDefault();
87168               }, {
87169                 passive: false
87170               }).on(_pointerPrefix + 'move.sidebar-resizer', pointermove).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', pointerup);
87171             }
87172
87173             function pointermove(d3_event) {
87174               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
87175               d3_event.preventDefault();
87176               var dx = d3_event.clientX - lastClientX;
87177               lastClientX = d3_event.clientX;
87178               var isRTL = _mainLocalizer.textDirection() === 'rtl';
87179               var scaleX = isRTL ? 0 : 1;
87180               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
87181               var x = containerLocGetter(d3_event)[0] - dragOffset;
87182               sidebarWidth = isRTL ? containerWidth - x : x;
87183               var isCollapsed = selection.classed('collapsed');
87184               var shouldCollapse = sidebarWidth < minWidth;
87185               selection.classed('collapsed', shouldCollapse);
87186
87187               if (shouldCollapse) {
87188                 if (!isCollapsed) {
87189                   selection.style(xMarginProperty, '-400px').style('width', '400px');
87190                   context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
87191                 }
87192               } else {
87193                 var widthPct = sidebarWidth / containerWidth * 100;
87194                 selection.style(xMarginProperty, null).style('width', widthPct + '%');
87195
87196                 if (isCollapsed) {
87197                   context.ui().onResize([-sidebarWidth * scaleX, 0]);
87198                 } else {
87199                   context.ui().onResize([-dx * scaleX, 0]);
87200                 }
87201               }
87202             }
87203
87204             function pointerup(d3_event) {
87205               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
87206               downPointerId = null;
87207               resizer.classed('dragging', false);
87208               select(window).on('touchmove.sidebar-resizer', null).on(_pointerPrefix + 'move.sidebar-resizer', null).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', null);
87209             }
87210
87211             var featureListWrap = selection.append('div').attr('class', 'feature-list-pane').call(uiFeatureList(context));
87212             var inspectorWrap = selection.append('div').attr('class', 'inspector-hidden inspector-wrap');
87213
87214             var hoverModeSelect = function hoverModeSelect(targets) {
87215               context.container().selectAll('.feature-list-item button').classed('hover', false);
87216
87217               if (context.selectedIDs().length > 1 && targets && targets.length) {
87218                 var elements = context.container().selectAll('.feature-list-item button').filter(function (node) {
87219                   return targets.indexOf(node) !== -1;
87220                 });
87221
87222                 if (!elements.empty()) {
87223                   elements.classed('hover', true);
87224                 }
87225               }
87226             };
87227
87228             sidebar.hoverModeSelect = throttle(hoverModeSelect, 200);
87229
87230             function hover(targets) {
87231               var datum = targets && targets.length && targets[0];
87232
87233               if (datum && datum.__featurehash__) {
87234                 // hovering on data
87235                 _wasData = true;
87236                 sidebar.show(dataEditor.datum(datum));
87237                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
87238               } else if (datum instanceof osmNote) {
87239                 if (context.mode().id === 'drag-note') return;
87240                 _wasNote = true;
87241                 var osm = services.osm;
87242
87243                 if (osm) {
87244                   datum = osm.getNote(datum.id); // marker may contain stale data - get latest
87245                 }
87246
87247                 sidebar.show(noteEditor.note(datum));
87248                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
87249               } else if (datum instanceof QAItem) {
87250                 _wasQaItem = true;
87251                 var errService = services[datum.service];
87252
87253                 if (errService) {
87254                   // marker may contain stale data - get latest
87255                   datum = errService.getError(datum.id);
87256                 } // Currently only three possible services
87257
87258
87259                 var errEditor;
87260
87261                 if (datum.service === 'keepRight') {
87262                   errEditor = keepRightEditor;
87263                 } else if (datum.service === 'osmose') {
87264                   errEditor = osmoseEditor;
87265                 } else {
87266                   errEditor = improveOsmEditor;
87267                 }
87268
87269                 context.container().selectAll('.qaItem.' + datum.service).classed('hover', function (d) {
87270                   return d.id === datum.id;
87271                 });
87272                 sidebar.show(errEditor.error(datum));
87273                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
87274               } else if (!_current && datum instanceof osmEntity) {
87275                 featureListWrap.classed('inspector-hidden', true);
87276                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', true);
87277
87278                 if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum.id]) || inspector.state() !== 'hover') {
87279                   inspector.state('hover').entityIDs([datum.id]).newFeature(false);
87280                   inspectorWrap.call(inspector);
87281                 }
87282               } else if (!_current) {
87283                 featureListWrap.classed('inspector-hidden', false);
87284                 inspectorWrap.classed('inspector-hidden', true);
87285                 inspector.state('hide');
87286               } else if (_wasData || _wasNote || _wasQaItem) {
87287                 _wasNote = false;
87288                 _wasData = false;
87289                 _wasQaItem = false;
87290                 context.container().selectAll('.note').classed('hover', false);
87291                 context.container().selectAll('.qaItem').classed('hover', false);
87292                 sidebar.hide();
87293               }
87294             }
87295
87296             sidebar.hover = throttle(hover, 200);
87297
87298             sidebar.intersects = function (extent) {
87299               var rect = selection.node().getBoundingClientRect();
87300               return extent.intersects([context.projection.invert([0, rect.height]), context.projection.invert([rect.width, 0])]);
87301             };
87302
87303             sidebar.select = function (ids, newFeature) {
87304               sidebar.hide();
87305
87306               if (ids && ids.length) {
87307                 var entity = ids.length === 1 && context.entity(ids[0]);
87308
87309                 if (entity && newFeature && selection.classed('collapsed')) {
87310                   // uncollapse the sidebar
87311                   var extent = entity.extent(context.graph());
87312                   sidebar.expand(sidebar.intersects(extent));
87313                 }
87314
87315                 featureListWrap.classed('inspector-hidden', true);
87316                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', false); // reload the UI even if the ids are the same since the entities
87317                 // themselves may have changed
87318
87319                 inspector.state('select').entityIDs(ids).newFeature(newFeature);
87320                 inspectorWrap.call(inspector);
87321               } else {
87322                 inspector.state('hide');
87323               }
87324             };
87325
87326             sidebar.showPresetList = function () {
87327               inspector.showList();
87328             };
87329
87330             sidebar.show = function (component, element) {
87331               featureListWrap.classed('inspector-hidden', true);
87332               inspectorWrap.classed('inspector-hidden', true);
87333               if (_current) _current.remove();
87334               _current = selection.append('div').attr('class', 'sidebar-component').call(component, element);
87335             };
87336
87337             sidebar.hide = function () {
87338               featureListWrap.classed('inspector-hidden', false);
87339               inspectorWrap.classed('inspector-hidden', true);
87340               if (_current) _current.remove();
87341               _current = null;
87342             };
87343
87344             sidebar.expand = function (moveMap) {
87345               if (selection.classed('collapsed')) {
87346                 sidebar.toggle(moveMap);
87347               }
87348             };
87349
87350             sidebar.collapse = function (moveMap) {
87351               if (!selection.classed('collapsed')) {
87352                 sidebar.toggle(moveMap);
87353               }
87354             };
87355
87356             sidebar.toggle = function (moveMap) {
87357               // Don't allow sidebar to toggle when the user is in the walkthrough.
87358               if (context.inIntro()) return;
87359               var isCollapsed = selection.classed('collapsed');
87360               var isCollapsing = !isCollapsed;
87361               var isRTL = _mainLocalizer.textDirection() === 'rtl';
87362               var scaleX = isRTL ? 0 : 1;
87363               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
87364               sidebarWidth = selection.node().getBoundingClientRect().width; // switch from % to px
87365
87366               selection.style('width', sidebarWidth + 'px');
87367               var startMargin, endMargin, lastMargin;
87368
87369               if (isCollapsing) {
87370                 startMargin = lastMargin = 0;
87371                 endMargin = -sidebarWidth;
87372               } else {
87373                 startMargin = lastMargin = -sidebarWidth;
87374                 endMargin = 0;
87375               }
87376
87377               if (!isCollapsing) {
87378                 // unhide the sidebar's content before it transitions onscreen
87379                 selection.classed('collapsed', isCollapsing);
87380               }
87381
87382               selection.transition().style(xMarginProperty, endMargin + 'px').tween('panner', function () {
87383                 var i = d3_interpolateNumber(startMargin, endMargin);
87384                 return function (t) {
87385                   var dx = lastMargin - Math.round(i(t));
87386                   lastMargin = lastMargin - dx;
87387                   context.ui().onResize(moveMap ? undefined : [dx * scaleX, 0]);
87388                 };
87389               }).on('end', function () {
87390                 if (isCollapsing) {
87391                   // hide the sidebar's content after it transitions offscreen
87392                   selection.classed('collapsed', isCollapsing);
87393                 } // switch back from px to %
87394
87395
87396                 if (!isCollapsing) {
87397                   var containerWidth = container.node().getBoundingClientRect().width;
87398                   var widthPct = sidebarWidth / containerWidth * 100;
87399                   selection.style(xMarginProperty, null).style('width', widthPct + '%');
87400                 }
87401               });
87402             }; // toggle the sidebar collapse when double-clicking the resizer
87403
87404
87405             resizer.on('dblclick', function (d3_event) {
87406               d3_event.preventDefault();
87407
87408               if (d3_event.sourceEvent) {
87409                 d3_event.sourceEvent.preventDefault();
87410               }
87411
87412               sidebar.toggle();
87413             }); // ensure hover sidebar is closed when zooming out beyond editable zoom
87414
87415             context.map().on('crossEditableZoom.sidebar', function (within) {
87416               if (!within && !selection.select('.inspector-hover').empty()) {
87417                 hover([]);
87418               }
87419             });
87420           }
87421
87422           sidebar.showPresetList = function () {};
87423
87424           sidebar.hover = function () {};
87425
87426           sidebar.hover.cancel = function () {};
87427
87428           sidebar.intersects = function () {};
87429
87430           sidebar.select = function () {};
87431
87432           sidebar.show = function () {};
87433
87434           sidebar.hide = function () {};
87435
87436           sidebar.expand = function () {};
87437
87438           sidebar.collapse = function () {};
87439
87440           sidebar.toggle = function () {};
87441
87442           return sidebar;
87443         }
87444
87445         function uiSourceSwitch(context) {
87446           var keys;
87447
87448           function click(d3_event) {
87449             d3_event.preventDefault();
87450             var osm = context.connection();
87451             if (!osm) return;
87452             if (context.inIntro()) return;
87453             if (context.history().hasChanges() && !window.confirm(_t('source_switch.lose_changes'))) return;
87454             var isLive = select(this).classed('live');
87455             isLive = !isLive;
87456             context.enter(modeBrowse(context));
87457             context.history().clearSaved(); // remove saved history
87458
87459             context.flush(); // remove stored data
87460
87461             select(this).html(isLive ? _t.html('source_switch.live') : _t.html('source_switch.dev')).classed('live', isLive).classed('chip', isLive);
87462             osm["switch"](isLive ? keys[0] : keys[1]); // switch connection (warning: dispatches 'change' event)
87463           }
87464
87465           var sourceSwitch = function sourceSwitch(selection) {
87466             selection.append('a').attr('href', '#').html(_t.html('source_switch.live')).attr('class', 'live chip').on('click', click);
87467           };
87468
87469           sourceSwitch.keys = function (_) {
87470             if (!arguments.length) return keys;
87471             keys = _;
87472             return sourceSwitch;
87473           };
87474
87475           return sourceSwitch;
87476         }
87477
87478         function uiSpinner(context) {
87479           var osm = context.connection();
87480           return function (selection) {
87481             var img = selection.append('img').attr('src', context.imagePath('loader-black.gif')).style('opacity', 0);
87482
87483             if (osm) {
87484               osm.on('loading.spinner', function () {
87485                 img.transition().style('opacity', 1);
87486               }).on('loaded.spinner', function () {
87487                 img.transition().style('opacity', 0);
87488               });
87489             }
87490           };
87491         }
87492
87493         function uiSplash(context) {
87494           return function (selection) {
87495             // Exception - if there are restorable changes, skip this splash screen.
87496             // This is because we currently only support one `uiModal` at a time
87497             //  and we need to show them `uiRestore`` instead of this one.
87498             if (context.history().hasRestorableChanges()) return; // If user has not seen this version of the privacy policy, show the splash again.
87499
87500             var updateMessage = '';
87501             var sawPrivacyVersion = corePreferences('sawPrivacyVersion');
87502             var showSplash = !corePreferences('sawSplash');
87503
87504             if (sawPrivacyVersion !== context.privacyVersion) {
87505               updateMessage = _t('splash.privacy_update');
87506               showSplash = true;
87507             }
87508
87509             if (!showSplash) return;
87510             corePreferences('sawSplash', true);
87511             corePreferences('sawPrivacyVersion', context.privacyVersion); // fetch intro graph data now, while user is looking at the splash screen
87512
87513             _mainFileFetcher.get('intro_graph');
87514             var modalSelection = uiModal(selection);
87515             modalSelection.select('.modal').attr('class', 'modal-splash modal');
87516             var introModal = modalSelection.select('.content').append('div').attr('class', 'fillL');
87517             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('splash.welcome'));
87518             var modalSection = introModal.append('div').attr('class', 'modal-section');
87519             modalSection.append('p').html(_t.html('splash.text', {
87520               version: context.version,
87521               website: '<a target="_blank" href="http://ideditor.blog/">ideditor.blog</a>',
87522               github: '<a target="_blank" href="https://github.com/openstreetmap/iD">github.com</a>'
87523             }));
87524             modalSection.append('p').html(_t.html('splash.privacy', {
87525               updateMessage: updateMessage,
87526               privacyLink: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t('splash.privacy_policy') + '</a>'
87527             }));
87528             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
87529             var walkthrough = buttonWrap.append('button').attr('class', 'walkthrough').on('click', function () {
87530               context.container().call(uiIntro(context));
87531               modalSelection.close();
87532             });
87533             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
87534             walkthrough.append('div').html(_t.html('splash.walkthrough'));
87535             var startEditing = buttonWrap.append('button').attr('class', 'start-editing').on('click', modalSelection.close);
87536             startEditing.append('svg').attr('class', 'logo logo-features').append('use').attr('xlink:href', '#iD-logo-features');
87537             startEditing.append('div').html(_t.html('splash.start'));
87538             modalSelection.select('button.close').attr('class', 'hide');
87539           };
87540         }
87541
87542         function uiStatus(context) {
87543           var osm = context.connection();
87544           return function (selection) {
87545             if (!osm) return;
87546
87547             function update(err, apiStatus) {
87548               selection.html('');
87549
87550               if (err) {
87551                 if (apiStatus === 'connectionSwitched') {
87552                   // if the connection was just switched, we can't rely on
87553                   // the status (we're getting the status of the previous api)
87554                   return;
87555                 } else if (apiStatus === 'rateLimited') {
87556                   selection.html(_t.html('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').html(_t.html('login')).on('click.login', function (d3_event) {
87557                     d3_event.preventDefault();
87558                     osm.authenticate();
87559                   });
87560                 } else {
87561                   // don't allow retrying too rapidly
87562                   var throttledRetry = throttle(function () {
87563                     // try loading the visible tiles
87564                     context.loadTiles(context.projection); // manually reload the status too in case all visible tiles were already loaded
87565
87566                     osm.reloadApiStatus();
87567                   }, 2000); // eslint-disable-next-line no-warning-comments
87568                   // TODO: nice messages for different error types
87569
87570
87571                   selection.html(_t.html('osm_api_status.message.error') + ' ').append('a').attr('href', '#') // let the user manually retry their connection directly
87572                   .html(_t.html('osm_api_status.retry')).on('click.retry', function (d3_event) {
87573                     d3_event.preventDefault();
87574                     throttledRetry();
87575                   });
87576                 }
87577               } else if (apiStatus === 'readonly') {
87578                 selection.html(_t.html('osm_api_status.message.readonly'));
87579               } else if (apiStatus === 'offline') {
87580                 selection.html(_t.html('osm_api_status.message.offline'));
87581               }
87582
87583               selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
87584             }
87585
87586             osm.on('apiStatusChange.uiStatus', update); // reload the status periodically regardless of other factors
87587
87588             window.setInterval(function () {
87589               osm.reloadApiStatus();
87590             }, 90000); // load the initial status in case no OSM data was loaded yet
87591
87592             osm.reloadApiStatus();
87593           };
87594         }
87595
87596         function modeDrawArea(context, wayID, startGraph, button) {
87597           var mode = {
87598             button: button,
87599             id: 'draw-area'
87600           };
87601           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawArea', function () {
87602             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.areas'))();
87603           });
87604           mode.wayID = wayID;
87605
87606           mode.enter = function () {
87607             context.install(behavior);
87608           };
87609
87610           mode.exit = function () {
87611             context.uninstall(behavior);
87612           };
87613
87614           mode.selectedIDs = function () {
87615             return [wayID];
87616           };
87617
87618           mode.activeID = function () {
87619             return behavior && behavior.activeID() || [];
87620           };
87621
87622           return mode;
87623         }
87624
87625         function modeAddArea(context, mode) {
87626           mode.id = 'add-area';
87627           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
87628           var defaultTags = {
87629             area: 'yes'
87630           };
87631           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'area');
87632
87633           function actionClose(wayId) {
87634             return function (graph) {
87635               return graph.replace(graph.entity(wayId).close());
87636             };
87637           }
87638
87639           function start(loc) {
87640             var startGraph = context.graph();
87641             var node = osmNode({
87642               loc: loc
87643             });
87644             var way = osmWay({
87645               tags: defaultTags
87646             });
87647             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
87648             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
87649           }
87650
87651           function startFromWay(loc, edge) {
87652             var startGraph = context.graph();
87653             var node = osmNode({
87654               loc: loc
87655             });
87656             var way = osmWay({
87657               tags: defaultTags
87658             });
87659             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id), actionAddMidpoint({
87660               loc: loc,
87661               edge: edge
87662             }, node));
87663             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
87664           }
87665
87666           function startFromNode(node) {
87667             var startGraph = context.graph();
87668             var way = osmWay({
87669               tags: defaultTags
87670             });
87671             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
87672             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
87673           }
87674
87675           mode.enter = function () {
87676             context.install(behavior);
87677           };
87678
87679           mode.exit = function () {
87680             context.uninstall(behavior);
87681           };
87682
87683           return mode;
87684         }
87685
87686         function modeAddLine(context, mode) {
87687           mode.id = 'add-line';
87688           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
87689           var defaultTags = {};
87690           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'line');
87691
87692           function start(loc) {
87693             var startGraph = context.graph();
87694             var node = osmNode({
87695               loc: loc
87696             });
87697             var way = osmWay({
87698               tags: defaultTags
87699             });
87700             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id));
87701             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
87702           }
87703
87704           function startFromWay(loc, edge) {
87705             var startGraph = context.graph();
87706             var node = osmNode({
87707               loc: loc
87708             });
87709             var way = osmWay({
87710               tags: defaultTags
87711             });
87712             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionAddMidpoint({
87713               loc: loc,
87714               edge: edge
87715             }, node));
87716             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
87717           }
87718
87719           function startFromNode(node) {
87720             var startGraph = context.graph();
87721             var way = osmWay({
87722               tags: defaultTags
87723             });
87724             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id));
87725             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
87726           }
87727
87728           mode.enter = function () {
87729             context.install(behavior);
87730           };
87731
87732           mode.exit = function () {
87733             context.uninstall(behavior);
87734           };
87735
87736           return mode;
87737         }
87738
87739         function modeAddPoint(context, mode) {
87740           mode.id = 'add-point';
87741           var behavior = behaviorDraw(context).on('click', add).on('clickWay', addWay).on('clickNode', addNode).on('cancel', cancel).on('finish', cancel);
87742           var defaultTags = {};
87743           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'point');
87744
87745           function add(loc) {
87746             var node = osmNode({
87747               loc: loc,
87748               tags: defaultTags
87749             });
87750             context.perform(actionAddEntity(node), _t('operations.add.annotation.point'));
87751             enterSelectMode(node);
87752           }
87753
87754           function addWay(loc, edge) {
87755             var node = osmNode({
87756               tags: defaultTags
87757             });
87758             context.perform(actionAddMidpoint({
87759               loc: loc,
87760               edge: edge
87761             }, node), _t('operations.add.annotation.vertex'));
87762             enterSelectMode(node);
87763           }
87764
87765           function enterSelectMode(node) {
87766             context.enter(modeSelect(context, [node.id]).newFeature(true));
87767           }
87768
87769           function addNode(node) {
87770             if (Object.keys(defaultTags).length === 0) {
87771               enterSelectMode(node);
87772               return;
87773             }
87774
87775             var tags = Object.assign({}, node.tags); // shallow copy
87776
87777             for (var key in defaultTags) {
87778               tags[key] = defaultTags[key];
87779             }
87780
87781             context.perform(actionChangeTags(node.id, tags), _t('operations.add.annotation.point'));
87782             enterSelectMode(node);
87783           }
87784
87785           function cancel() {
87786             context.enter(modeBrowse(context));
87787           }
87788
87789           mode.enter = function () {
87790             context.install(behavior);
87791           };
87792
87793           mode.exit = function () {
87794             context.uninstall(behavior);
87795           };
87796
87797           return mode;
87798         }
87799
87800         function modeSelectNote(context, selectedNoteID) {
87801           var mode = {
87802             id: 'select-note',
87803             button: 'browse'
87804           };
87805
87806           var _keybinding = utilKeybinding('select-note');
87807
87808           var _noteEditor = uiNoteEditor(context).on('change', function () {
87809             context.map().pan([0, 0]); // trigger a redraw
87810
87811             var note = checkSelectedID();
87812             if (!note) return;
87813             context.ui().sidebar.show(_noteEditor.note(note));
87814           });
87815
87816           var _behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
87817           var _newFeature = false;
87818
87819           function checkSelectedID() {
87820             if (!services.osm) return;
87821             var note = services.osm.getNote(selectedNoteID);
87822
87823             if (!note) {
87824               context.enter(modeBrowse(context));
87825             }
87826
87827             return note;
87828           } // class the note as selected, or return to browse mode if the note is gone
87829
87830
87831           function selectNote(d3_event, drawn) {
87832             if (!checkSelectedID()) return;
87833             var selection = context.surface().selectAll('.layer-notes .note-' + selectedNoteID);
87834
87835             if (selection.empty()) {
87836               // Return to browse mode if selected DOM elements have
87837               // disappeared because the user moved them out of view..
87838               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
87839
87840               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
87841                 context.enter(modeBrowse(context));
87842               }
87843             } else {
87844               selection.classed('selected', true);
87845               context.selectedNoteID(selectedNoteID);
87846             }
87847           }
87848
87849           function esc() {
87850             if (context.container().select('.combobox').size()) return;
87851             context.enter(modeBrowse(context));
87852           }
87853
87854           mode.zoomToSelected = function () {
87855             if (!services.osm) return;
87856             var note = services.osm.getNote(selectedNoteID);
87857
87858             if (note) {
87859               context.map().centerZoomEase(note.loc, 20);
87860             }
87861           };
87862
87863           mode.newFeature = function (val) {
87864             if (!arguments.length) return _newFeature;
87865             _newFeature = val;
87866             return mode;
87867           };
87868
87869           mode.enter = function () {
87870             var note = checkSelectedID();
87871             if (!note) return;
87872
87873             _behaviors.forEach(context.install);
87874
87875             _keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
87876
87877             select(document).call(_keybinding);
87878             selectNote();
87879             var sidebar = context.ui().sidebar;
87880             sidebar.show(_noteEditor.note(note).newNote(_newFeature)); // expand the sidebar, avoid obscuring the note if needed
87881
87882             sidebar.expand(sidebar.intersects(note.extent()));
87883             context.map().on('drawn.select', selectNote);
87884           };
87885
87886           mode.exit = function () {
87887             _behaviors.forEach(context.uninstall);
87888
87889             select(document).call(_keybinding.unbind);
87890             context.surface().selectAll('.layer-notes .selected').classed('selected hover', false);
87891             context.map().on('drawn.select', null);
87892             context.ui().sidebar.hide();
87893             context.selectedNoteID(null);
87894           };
87895
87896           return mode;
87897         }
87898
87899         function modeAddNote(context) {
87900           var mode = {
87901             id: 'add-note',
87902             button: 'note',
87903             description: _t.html('modes.add_note.description'),
87904             key: _t('modes.add_note.key')
87905           };
87906           var behavior = behaviorDraw(context).on('click', add).on('cancel', cancel).on('finish', cancel);
87907
87908           function add(loc) {
87909             var osm = services.osm;
87910             if (!osm) return;
87911             var note = osmNote({
87912               loc: loc,
87913               status: 'open',
87914               comments: []
87915             });
87916             osm.replaceNote(note); // force a reraw (there is no history change that would otherwise do this)
87917
87918             context.map().pan([0, 0]);
87919             context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
87920           }
87921
87922           function cancel() {
87923             context.enter(modeBrowse(context));
87924           }
87925
87926           mode.enter = function () {
87927             context.install(behavior);
87928           };
87929
87930           mode.exit = function () {
87931             context.uninstall(behavior);
87932           };
87933
87934           return mode;
87935         }
87936
87937         var JXON = new function () {
87938           var sValueProp = 'keyValue',
87939               sAttributesProp = 'keyAttributes',
87940               sAttrPref = '@',
87941
87942           /* you can customize these values */
87943           aCache = [],
87944               rIsNull = /^\s*$/,
87945               rIsBool = /^(?:true|false)$/i;
87946
87947           function parseText(sValue) {
87948             if (rIsNull.test(sValue)) {
87949               return null;
87950             }
87951
87952             if (rIsBool.test(sValue)) {
87953               return sValue.toLowerCase() === 'true';
87954             }
87955
87956             if (isFinite(sValue)) {
87957               return parseFloat(sValue);
87958             }
87959
87960             if (isFinite(Date.parse(sValue))) {
87961               return new Date(sValue);
87962             }
87963
87964             return sValue;
87965           }
87966
87967           function EmptyTree() {}
87968
87969           EmptyTree.prototype.toString = function () {
87970             return 'null';
87971           };
87972
87973           EmptyTree.prototype.valueOf = function () {
87974             return null;
87975           };
87976
87977           function objectify(vValue) {
87978             return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
87979           }
87980
87981           function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
87982             var nLevelStart = aCache.length,
87983                 bChildren = oParentNode.hasChildNodes(),
87984                 bAttributes = oParentNode.hasAttributes(),
87985                 bHighVerb = Boolean(nVerb & 2);
87986             var sProp,
87987                 vContent,
87988                 nLength = 0,
87989                 sCollectedTxt = '',
87990                 vResult = bHighVerb ? {} :
87991             /* put here the default value for empty nodes: */
87992             true;
87993
87994             if (bChildren) {
87995               for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
87996                 oNode = oParentNode.childNodes.item(nItem);
87997
87998                 if (oNode.nodeType === 4) {
87999                   /* nodeType is 'CDATASection' (4) */
88000                   sCollectedTxt += oNode.nodeValue;
88001                 } else if (oNode.nodeType === 3) {
88002                   /* nodeType is 'Text' (3) */
88003                   sCollectedTxt += oNode.nodeValue.trim();
88004                 } else if (oNode.nodeType === 1 && !oNode.prefix) {
88005                   /* nodeType is 'Element' (1) */
88006                   aCache.push(oNode);
88007                 }
88008               }
88009             }
88010
88011             var nLevelEnd = aCache.length,
88012                 vBuiltVal = parseText(sCollectedTxt);
88013
88014             if (!bHighVerb && (bChildren || bAttributes)) {
88015               vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
88016             }
88017
88018             for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
88019               sProp = aCache[nElId].nodeName.toLowerCase();
88020               vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
88021
88022               if (vResult.hasOwnProperty(sProp)) {
88023                 if (vResult[sProp].constructor !== Array) {
88024                   vResult[sProp] = [vResult[sProp]];
88025                 }
88026
88027                 vResult[sProp].push(vContent);
88028               } else {
88029                 vResult[sProp] = vContent;
88030                 nLength++;
88031               }
88032             }
88033
88034             if (bAttributes) {
88035               var nAttrLen = oParentNode.attributes.length,
88036                   sAPrefix = bNesteAttr ? '' : sAttrPref,
88037                   oAttrParent = bNesteAttr ? {} : vResult;
88038
88039               for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
88040                 oAttrib = oParentNode.attributes.item(nAttrib);
88041                 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
88042               }
88043
88044               if (bNesteAttr) {
88045                 if (bFreeze) {
88046                   Object.freeze(oAttrParent);
88047                 }
88048
88049                 vResult[sAttributesProp] = oAttrParent;
88050                 nLength -= nAttrLen - 1;
88051               }
88052             }
88053
88054             if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
88055               vResult[sValueProp] = vBuiltVal;
88056             } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
88057               vResult = vBuiltVal;
88058             }
88059
88060             if (bFreeze && (bHighVerb || nLength > 0)) {
88061               Object.freeze(vResult);
88062             }
88063
88064             aCache.length = nLevelStart;
88065             return vResult;
88066           }
88067
88068           function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
88069             var vValue, oChild;
88070
88071             if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
88072               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
88073               /* verbosity level is 0 */
88074             } else if (oParentObj.constructor === Date) {
88075               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
88076             }
88077
88078             for (var sName in oParentObj) {
88079               vValue = oParentObj[sName];
88080
88081               if (isFinite(sName) || vValue instanceof Function) {
88082                 continue;
88083               }
88084               /* verbosity level is 0 */
88085
88086
88087               if (sName === sValueProp) {
88088                 if (vValue !== null && vValue !== true) {
88089                   oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
88090                 }
88091               } else if (sName === sAttributesProp) {
88092                 /* verbosity level is 3 */
88093                 for (var sAttrib in vValue) {
88094                   oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
88095                 }
88096               } else if (sName.charAt(0) === sAttrPref) {
88097                 oParentEl.setAttribute(sName.slice(1), vValue);
88098               } else if (vValue.constructor === Array) {
88099                 for (var nItem = 0; nItem < vValue.length; nItem++) {
88100                   oChild = oXMLDoc.createElement(sName);
88101                   loadObjTree(oXMLDoc, oChild, vValue[nItem]);
88102                   oParentEl.appendChild(oChild);
88103                 }
88104               } else {
88105                 oChild = oXMLDoc.createElement(sName);
88106
88107                 if (vValue instanceof Object) {
88108                   loadObjTree(oXMLDoc, oChild, vValue);
88109                 } else if (vValue !== null && vValue !== true) {
88110                   oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
88111                 }
88112
88113                 oParentEl.appendChild(oChild);
88114               }
88115             }
88116           }
88117
88118           this.build = function (oXMLParent, nVerbosity
88119           /* optional */
88120           , bFreeze
88121           /* optional */
88122           , bNesteAttributes
88123           /* optional */
88124           ) {
88125             var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 :
88126             /* put here the default verbosity level: */
88127             1;
88128
88129             return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
88130           };
88131
88132           this.unbuild = function (oObjTree) {
88133             var oNewDoc = document.implementation.createDocument('', '', null);
88134             loadObjTree(oNewDoc, oNewDoc, oObjTree);
88135             return oNewDoc;
88136           };
88137
88138           this.stringify = function (oObjTree) {
88139             return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
88140           };
88141         }(); // var myObject = JXON.build(doc);
88142         // we got our javascript object! try: alert(JSON.stringify(myObject));
88143         // var newDoc = JXON.unbuild(myObject);
88144         // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
88145
88146         function uiConflicts(context) {
88147           var dispatch = dispatch$8('cancel', 'save');
88148           var keybinding = utilKeybinding('conflicts');
88149
88150           var _origChanges;
88151
88152           var _conflictList;
88153
88154           var _shownConflictIndex;
88155
88156           function keybindingOn() {
88157             select(document).call(keybinding.on('⎋', cancel, true));
88158           }
88159
88160           function keybindingOff() {
88161             select(document).call(keybinding.unbind);
88162           }
88163
88164           function tryAgain() {
88165             keybindingOff();
88166             dispatch.call('save');
88167           }
88168
88169           function cancel() {
88170             keybindingOff();
88171             dispatch.call('cancel');
88172           }
88173
88174           function conflicts(selection) {
88175             keybindingOn();
88176             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
88177             headerEnter.append('button').attr('class', 'fr').on('click', cancel).call(svgIcon('#iD-icon-close'));
88178             headerEnter.append('h3').html(_t.html('save.conflict.header'));
88179             var bodyEnter = selection.selectAll('.body').data([0]).enter().append('div').attr('class', 'body fillL');
88180             var conflictsHelpEnter = bodyEnter.append('div').attr('class', 'conflicts-help').html(_t.html('save.conflict.help')); // Download changes link
88181
88182             var detected = utilDetect();
88183             var changeset = new osmChangeset();
88184             delete changeset.id; // Export without changeset_id
88185
88186             var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
88187             var blob = new Blob([data], {
88188               type: 'text/xml;charset=utf-8;'
88189             });
88190             var fileName = 'changes.osc';
88191             var linkEnter = conflictsHelpEnter.selectAll('.download-changes').append('a').attr('class', 'download-changes');
88192
88193             if (detected.download) {
88194               // All except IE11 and Edge
88195               linkEnter // download the data as a file
88196               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
88197             } else {
88198               // IE11 and Edge
88199               linkEnter // open data uri in a new tab
88200               .attr('target', '_blank').on('click.download', function () {
88201                 navigator.msSaveBlob(blob, fileName);
88202               });
88203             }
88204
88205             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('save.conflict.download_changes'));
88206             bodyEnter.append('div').attr('class', 'conflict-container fillL3').call(showConflict, 0);
88207             bodyEnter.append('div').attr('class', 'conflicts-done').attr('opacity', 0).style('display', 'none').html(_t.html('save.conflict.done'));
88208             var buttonsEnter = bodyEnter.append('div').attr('class', 'buttons col12 joined conflicts-buttons');
88209             buttonsEnter.append('button').attr('disabled', _conflictList.length > 1).attr('class', 'action conflicts-button col6').html(_t.html('save.title')).on('click.try_again', tryAgain);
88210             buttonsEnter.append('button').attr('class', 'secondary-action conflicts-button col6').html(_t.html('confirm.cancel')).on('click.cancel', cancel);
88211           }
88212
88213           function showConflict(selection, index) {
88214             index = utilWrap(index, _conflictList.length);
88215             _shownConflictIndex = index;
88216             var parent = select(selection.node().parentNode); // enable save button if this is the last conflict being reviewed..
88217
88218             if (index === _conflictList.length - 1) {
88219               window.setTimeout(function () {
88220                 parent.select('.conflicts-button').attr('disabled', null);
88221                 parent.select('.conflicts-done').transition().attr('opacity', 1).style('display', 'block');
88222               }, 250);
88223             }
88224
88225             var conflict = selection.selectAll('.conflict').data([_conflictList[index]]);
88226             conflict.exit().remove();
88227             var conflictEnter = conflict.enter().append('div').attr('class', 'conflict');
88228             conflictEnter.append('h4').attr('class', 'conflict-count').html(_t.html('save.conflict.count', {
88229               num: index + 1,
88230               total: _conflictList.length
88231             }));
88232             conflictEnter.append('a').attr('class', 'conflict-description').attr('href', '#').html(function (d) {
88233               return d.name;
88234             }).on('click', function (d3_event, d) {
88235               d3_event.preventDefault();
88236               zoomToEntity(d.id);
88237             });
88238             var details = conflictEnter.append('div').attr('class', 'conflict-detail-container');
88239             details.append('ul').attr('class', 'conflict-detail-list').selectAll('li').data(function (d) {
88240               return d.details || [];
88241             }).enter().append('li').attr('class', 'conflict-detail-item').html(function (d) {
88242               return d;
88243             });
88244             details.append('div').attr('class', 'conflict-choices').call(addChoices);
88245             details.append('div').attr('class', 'conflict-nav-buttons joined cf').selectAll('button').data(['previous', 'next']).enter().append('button').html(function (d) {
88246               return _t.html('save.conflict.' + d);
88247             }).attr('class', 'conflict-nav-button action col6').attr('disabled', function (d, i) {
88248               return i === 0 && index === 0 || i === 1 && index === _conflictList.length - 1 || null;
88249             }).on('click', function (d3_event, d) {
88250               d3_event.preventDefault();
88251               var container = parent.selectAll('.conflict-container');
88252               var sign = d === 'previous' ? -1 : 1;
88253               container.selectAll('.conflict').remove();
88254               container.call(showConflict, index + sign);
88255             });
88256           }
88257
88258           function addChoices(selection) {
88259             var choices = selection.append('ul').attr('class', 'layer-list').selectAll('li').data(function (d) {
88260               return d.choices || [];
88261             }); // enter
88262
88263             var choicesEnter = choices.enter().append('li').attr('class', 'layer');
88264             var labelEnter = choicesEnter.append('label');
88265             labelEnter.append('input').attr('type', 'radio').attr('name', function (d) {
88266               return d.id;
88267             }).on('change', function (d3_event, d) {
88268               var ul = this.parentNode.parentNode.parentNode;
88269               ul.__data__.chosen = d.id;
88270               choose(d3_event, ul, d);
88271             });
88272             labelEnter.append('span').html(function (d) {
88273               return d.text;
88274             }); // update
88275
88276             choicesEnter.merge(choices).each(function (d) {
88277               var ul = this.parentNode;
88278
88279               if (ul.__data__.chosen === d.id) {
88280                 choose(null, ul, d);
88281               }
88282             });
88283           }
88284
88285           function choose(d3_event, ul, datum) {
88286             if (d3_event) d3_event.preventDefault();
88287             select(ul).selectAll('li').classed('active', function (d) {
88288               return d === datum;
88289             }).selectAll('input').property('checked', function (d) {
88290               return d === datum;
88291             });
88292             var extent = geoExtent();
88293             var entity;
88294             entity = context.graph().hasEntity(datum.id);
88295             if (entity) extent._extend(entity.extent(context.graph()));
88296             datum.action();
88297             entity = context.graph().hasEntity(datum.id);
88298             if (entity) extent._extend(entity.extent(context.graph()));
88299             zoomToEntity(datum.id, extent);
88300           }
88301
88302           function zoomToEntity(id, extent) {
88303             context.surface().selectAll('.hover').classed('hover', false);
88304             var entity = context.graph().hasEntity(id);
88305
88306             if (entity) {
88307               if (extent) {
88308                 context.map().trimmedExtent(extent);
88309               } else {
88310                 context.map().zoomToEase(entity);
88311               }
88312
88313               context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
88314             }
88315           } // The conflict list should be an array of objects like:
88316           // {
88317           //     id: id,
88318           //     name: entityName(local),
88319           //     details: merge.conflicts(),
88320           //     chosen: 1,
88321           //     choices: [
88322           //         choice(id, keepMine, forceLocal),
88323           //         choice(id, keepTheirs, forceRemote)
88324           //     ]
88325           // }
88326
88327
88328           conflicts.conflictList = function (_) {
88329             if (!arguments.length) return _conflictList;
88330             _conflictList = _;
88331             return conflicts;
88332           };
88333
88334           conflicts.origChanges = function (_) {
88335             if (!arguments.length) return _origChanges;
88336             _origChanges = _;
88337             return conflicts;
88338           };
88339
88340           conflicts.shownEntityIds = function () {
88341             if (_conflictList && typeof _shownConflictIndex === 'number') {
88342               return [_conflictList[_shownConflictIndex].id];
88343             }
88344
88345             return [];
88346           };
88347
88348           return utilRebind(conflicts, dispatch, 'on');
88349         }
88350
88351         function uiConfirm(selection) {
88352           var modalSelection = uiModal(selection);
88353           modalSelection.select('.modal').classed('modal-alert', true);
88354           var section = modalSelection.select('.content');
88355           section.append('div').attr('class', 'modal-section header');
88356           section.append('div').attr('class', 'modal-section message-text');
88357           var buttons = section.append('div').attr('class', 'modal-section buttons cf');
88358
88359           modalSelection.okButton = function () {
88360             buttons.append('button').attr('class', 'button ok-button action').on('click.confirm', function () {
88361               modalSelection.remove();
88362             }).html(_t.html('confirm.okay')).node().focus();
88363             return modalSelection;
88364           };
88365
88366           return modalSelection;
88367         }
88368
88369         function uiChangesetEditor(context) {
88370           var dispatch = dispatch$8('change');
88371           var formFields = uiFormFields(context);
88372           var commentCombo = uiCombobox(context, 'comment').caseSensitive(true);
88373
88374           var _fieldsArr;
88375
88376           var _tags;
88377
88378           var _changesetID;
88379
88380           function changesetEditor(selection) {
88381             render(selection);
88382           }
88383
88384           function render(selection) {
88385             var initial = false;
88386
88387             if (!_fieldsArr) {
88388               initial = true;
88389               var presets = _mainPresetIndex;
88390               _fieldsArr = [uiField(context, presets.field('comment'), null, {
88391                 show: true,
88392                 revert: false
88393               }), uiField(context, presets.field('source'), null, {
88394                 show: false,
88395                 revert: false
88396               }), uiField(context, presets.field('hashtags'), null, {
88397                 show: false,
88398                 revert: false
88399               })];
88400
88401               _fieldsArr.forEach(function (field) {
88402                 field.on('change', function (t, onInput) {
88403                   dispatch.call('change', field, undefined, t, onInput);
88404                 });
88405               });
88406             }
88407
88408             _fieldsArr.forEach(function (field) {
88409               field.tags(_tags);
88410             });
88411
88412             selection.call(formFields.fieldsArr(_fieldsArr));
88413
88414             if (initial) {
88415               var commentField = selection.select('.form-field-comment textarea');
88416               var commentNode = commentField.node();
88417
88418               if (commentNode) {
88419                 commentNode.focus();
88420                 commentNode.select();
88421               } // trigger a 'blur' event so that comment field can be cleaned
88422               // and checked for hashtags, even if retrieved from localstorage
88423
88424
88425               utilTriggerEvent(commentField, 'blur');
88426               var osm = context.connection();
88427
88428               if (osm) {
88429                 osm.userChangesets(function (err, changesets) {
88430                   if (err) return;
88431                   var comments = changesets.map(function (changeset) {
88432                     var comment = changeset.tags.comment;
88433                     return comment ? {
88434                       title: comment,
88435                       value: comment
88436                     } : null;
88437                   }).filter(Boolean);
88438                   commentField.call(commentCombo.data(utilArrayUniqBy(comments, 'title')));
88439                 });
88440               }
88441             } // Add warning if comment mentions Google
88442
88443
88444             var hasGoogle = _tags.comment.match(/google/i);
88445
88446             var commentWarning = selection.select('.form-field-comment').selectAll('.comment-warning').data(hasGoogle ? [0] : []);
88447             commentWarning.exit().transition().duration(200).style('opacity', 0).remove();
88448             var commentEnter = commentWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning comment-warning').style('opacity', 0);
88449             commentEnter.append('a').attr('target', '_blank').call(svgIcon('#iD-icon-alert', 'inline')).attr('href', _t('commit.google_warning_link')).append('span').html(_t.html('commit.google_warning'));
88450             commentEnter.transition().duration(200).style('opacity', 1);
88451           }
88452
88453           changesetEditor.tags = function (_) {
88454             if (!arguments.length) return _tags;
88455             _tags = _; // Don't reset _fieldsArr here.
88456
88457             return changesetEditor;
88458           };
88459
88460           changesetEditor.changesetID = function (_) {
88461             if (!arguments.length) return _changesetID;
88462             if (_changesetID === _) return changesetEditor;
88463             _changesetID = _;
88464             _fieldsArr = null;
88465             return changesetEditor;
88466           };
88467
88468           return utilRebind(changesetEditor, dispatch, 'on');
88469         }
88470
88471         function uiSectionChanges(context) {
88472           var detected = utilDetect();
88473           var _discardTags = {};
88474           _mainFileFetcher.get('discarded').then(function (d) {
88475             _discardTags = d;
88476           })["catch"](function () {
88477             /* ignore */
88478           });
88479           var section = uiSection('changes-list', context).label(function () {
88480             var history = context.history();
88481             var summary = history.difference().summary();
88482             return _t('inspector.title_count', {
88483               title: _t.html('commit.changes'),
88484               count: summary.length
88485             });
88486           }).disclosureContent(renderDisclosureContent);
88487
88488           function renderDisclosureContent(selection) {
88489             var history = context.history();
88490             var summary = history.difference().summary();
88491             var container = selection.selectAll('.commit-section').data([0]);
88492             var containerEnter = container.enter().append('div').attr('class', 'commit-section');
88493             containerEnter.append('ul').attr('class', 'changeset-list');
88494             container = containerEnter.merge(container);
88495             var items = container.select('ul').selectAll('li').data(summary);
88496             var itemsEnter = items.enter().append('li').attr('class', 'change-item');
88497             var buttons = itemsEnter.append('button').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
88498             buttons.each(function (d) {
88499               select(this).call(svgIcon('#iD-icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
88500             });
88501             buttons.append('span').attr('class', 'change-type').html(function (d) {
88502               return _t.html('commit.' + d.changeType) + ' ';
88503             });
88504             buttons.append('strong').attr('class', 'entity-type').html(function (d) {
88505               var matched = _mainPresetIndex.match(d.entity, d.graph);
88506               return matched && matched.name() || utilDisplayType(d.entity.id);
88507             });
88508             buttons.append('span').attr('class', 'entity-name').html(function (d) {
88509               var name = utilDisplayName(d.entity) || '',
88510                   string = '';
88511
88512               if (name !== '') {
88513                 string += ':';
88514               }
88515
88516               return string += ' ' + name;
88517             });
88518             items = itemsEnter.merge(items); // Download changeset link
88519
88520             var changeset = new osmChangeset().update({
88521               id: undefined
88522             });
88523             var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
88524             delete changeset.id; // Export without chnageset_id
88525
88526             var data = JXON.stringify(changeset.osmChangeJXON(changes));
88527             var blob = new Blob([data], {
88528               type: 'text/xml;charset=utf-8;'
88529             });
88530             var fileName = 'changes.osc';
88531             var linkEnter = container.selectAll('.download-changes').data([0]).enter().append('a').attr('class', 'download-changes');
88532
88533             if (detected.download) {
88534               // All except IE11 and Edge
88535               linkEnter // download the data as a file
88536               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
88537             } else {
88538               // IE11 and Edge
88539               linkEnter // open data uri in a new tab
88540               .attr('target', '_blank').on('click.download', function () {
88541                 navigator.msSaveBlob(blob, fileName);
88542               });
88543             }
88544
88545             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('commit.download_changes'));
88546
88547             function mouseover(d) {
88548               if (d.entity) {
88549                 context.surface().selectAll(utilEntityOrMemberSelector([d.entity.id], context.graph())).classed('hover', true);
88550               }
88551             }
88552
88553             function mouseout() {
88554               context.surface().selectAll('.hover').classed('hover', false);
88555             }
88556
88557             function click(d3_event, change) {
88558               if (change.changeType !== 'deleted') {
88559                 var entity = change.entity;
88560                 context.map().zoomToEase(entity);
88561                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
88562               }
88563             }
88564           }
88565
88566           return section;
88567         }
88568
88569         function uiCommitWarnings(context) {
88570           function commitWarnings(selection) {
88571             var issuesBySeverity = context.validator().getIssuesBySeverity({
88572               what: 'edited',
88573               where: 'all',
88574               includeDisabledRules: true
88575             });
88576
88577             for (var severity in issuesBySeverity) {
88578               var issues = issuesBySeverity[severity];
88579               var section = severity + '-section';
88580               var issueItem = severity + '-item';
88581               var container = selection.selectAll('.' + section).data(issues.length ? [0] : []);
88582               container.exit().remove();
88583               var containerEnter = container.enter().append('div').attr('class', 'modal-section ' + section + ' fillL2');
88584               containerEnter.append('h3').html(severity === 'warning' ? _t.html('commit.warnings') : _t.html('commit.errors'));
88585               containerEnter.append('ul').attr('class', 'changeset-list');
88586               container = containerEnter.merge(container);
88587               var items = container.select('ul').selectAll('li').data(issues, function (d) {
88588                 return d.id;
88589               });
88590               items.exit().remove();
88591               var itemsEnter = items.enter().append('li').attr('class', issueItem);
88592               var buttons = itemsEnter.append('button').on('mouseover', function (d3_event, d) {
88593                 if (d.entityIds) {
88594                   context.surface().selectAll(utilEntityOrMemberSelector(d.entityIds, context.graph())).classed('hover', true);
88595                 }
88596               }).on('mouseout', function () {
88597                 context.surface().selectAll('.hover').classed('hover', false);
88598               }).on('click', function (d3_event, d) {
88599                 context.validator().focusIssue(d);
88600               });
88601               buttons.call(svgIcon('#iD-icon-alert', 'pre-text'));
88602               buttons.append('strong').attr('class', 'issue-message');
88603               buttons.filter(function (d) {
88604                 return d.tooltip;
88605               }).call(uiTooltip().title(function (d) {
88606                 return d.tooltip;
88607               }).placement('top'));
88608               items = itemsEnter.merge(items);
88609               items.selectAll('.issue-message').html(function (d) {
88610                 return d.message(context);
88611               });
88612             }
88613           }
88614
88615           return commitWarnings;
88616         }
88617
88618         var readOnlyTags = [/^changesets_count$/, /^created_by$/, /^ideditor:/, /^imagery_used$/, /^host$/, /^locale$/, /^warnings:/, /^resolved:/, /^closed:note$/, /^closed:keepright$/, /^closed:improveosm:/, /^closed:osmose:/]; // treat most punctuation (except -, _, +, &) as hashtag delimiters - #4398
88619         // from https://stackoverflow.com/a/25575009
88620
88621         var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
88622         function uiCommit(context) {
88623           var dispatch = dispatch$8('cancel');
88624
88625           var _userDetails;
88626
88627           var _selection;
88628
88629           var changesetEditor = uiChangesetEditor(context).on('change', changeTags);
88630           var rawTagEditor = uiSectionRawTagEditor('changeset-tag-editor', context).on('change', changeTags).readOnlyTags(readOnlyTags);
88631           var commitChanges = uiSectionChanges(context);
88632           var commitWarnings = uiCommitWarnings(context);
88633
88634           function commit(selection) {
88635             _selection = selection; // Initialize changeset if one does not exist yet.
88636
88637             if (!context.changeset) initChangeset();
88638             loadDerivedChangesetTags();
88639             selection.call(render);
88640           }
88641
88642           function initChangeset() {
88643             // expire stored comment, hashtags, source after cutoff datetime - #3947 #4899
88644             var commentDate = +corePreferences('commentDate') || 0;
88645             var currDate = Date.now();
88646             var cutoff = 2 * 86400 * 1000; // 2 days
88647
88648             if (commentDate > currDate || currDate - commentDate > cutoff) {
88649               corePreferences('comment', null);
88650               corePreferences('hashtags', null);
88651               corePreferences('source', null);
88652             } // load in explicitly-set values, if any
88653
88654
88655             if (context.defaultChangesetComment()) {
88656               corePreferences('comment', context.defaultChangesetComment());
88657               corePreferences('commentDate', Date.now());
88658             }
88659
88660             if (context.defaultChangesetSource()) {
88661               corePreferences('source', context.defaultChangesetSource());
88662               corePreferences('commentDate', Date.now());
88663             }
88664
88665             if (context.defaultChangesetHashtags()) {
88666               corePreferences('hashtags', context.defaultChangesetHashtags());
88667               corePreferences('commentDate', Date.now());
88668             }
88669
88670             var detected = utilDetect();
88671             var tags = {
88672               comment: corePreferences('comment') || '',
88673               created_by: context.cleanTagValue('iD ' + context.version),
88674               host: context.cleanTagValue(detected.host),
88675               locale: context.cleanTagValue(_mainLocalizer.localeCode())
88676             }; // call findHashtags initially - this will remove stored
88677             // hashtags if any hashtags are found in the comment - #4304
88678
88679             findHashtags(tags, true);
88680             var hashtags = corePreferences('hashtags');
88681
88682             if (hashtags) {
88683               tags.hashtags = hashtags;
88684             }
88685
88686             var source = corePreferences('source');
88687
88688             if (source) {
88689               tags.source = source;
88690             }
88691
88692             var photoOverlaysUsed = context.history().photoOverlaysUsed();
88693
88694             if (photoOverlaysUsed.length) {
88695               var sources = (tags.source || '').split(';'); // include this tag for any photo layer
88696
88697               if (sources.indexOf('streetlevel imagery') === -1) {
88698                 sources.push('streetlevel imagery');
88699               } // add the photo overlays used during editing as sources
88700
88701
88702               photoOverlaysUsed.forEach(function (photoOverlay) {
88703                 if (sources.indexOf(photoOverlay) === -1) {
88704                   sources.push(photoOverlay);
88705                 }
88706               });
88707               tags.source = context.cleanTagValue(sources.join(';'));
88708             }
88709
88710             context.changeset = new osmChangeset({
88711               tags: tags
88712             });
88713           } // Calculates read-only metadata tags based on the user's editing session and applies
88714           // them to the changeset.
88715
88716
88717           function loadDerivedChangesetTags() {
88718             var osm = context.connection();
88719             if (!osm) return;
88720             var tags = Object.assign({}, context.changeset.tags); // shallow copy
88721             // assign tags for imagery used
88722
88723             var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(';'));
88724             tags.imagery_used = imageryUsed || 'None'; // assign tags for closed issues and notes
88725
88726             var osmClosed = osm.getClosedIDs();
88727             var itemType;
88728
88729             if (osmClosed.length) {
88730               tags['closed:note'] = context.cleanTagValue(osmClosed.join(';'));
88731             }
88732
88733             if (services.keepRight) {
88734               var krClosed = services.keepRight.getClosedIDs();
88735
88736               if (krClosed.length) {
88737                 tags['closed:keepright'] = context.cleanTagValue(krClosed.join(';'));
88738               }
88739             }
88740
88741             if (services.improveOSM) {
88742               var iOsmClosed = services.improveOSM.getClosedCounts();
88743
88744               for (itemType in iOsmClosed) {
88745                 tags['closed:improveosm:' + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
88746               }
88747             }
88748
88749             if (services.osmose) {
88750               var osmoseClosed = services.osmose.getClosedCounts();
88751
88752               for (itemType in osmoseClosed) {
88753                 tags['closed:osmose:' + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
88754               }
88755             } // remove existing issue counts
88756
88757
88758             for (var key in tags) {
88759               if (key.match(/(^warnings:)|(^resolved:)/)) {
88760                 delete tags[key];
88761               }
88762             }
88763
88764             function addIssueCounts(issues, prefix) {
88765               var issuesByType = utilArrayGroupBy(issues, 'type');
88766
88767               for (var issueType in issuesByType) {
88768                 var issuesOfType = issuesByType[issueType];
88769
88770                 if (issuesOfType[0].subtype) {
88771                   var issuesBySubtype = utilArrayGroupBy(issuesOfType, 'subtype');
88772
88773                   for (var issueSubtype in issuesBySubtype) {
88774                     var issuesOfSubtype = issuesBySubtype[issueSubtype];
88775                     tags[prefix + ':' + issueType + ':' + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
88776                   }
88777                 } else {
88778                   tags[prefix + ':' + issueType] = context.cleanTagValue(issuesOfType.length.toString());
88779                 }
88780               }
88781             } // add counts of warnings generated by the user's edits
88782
88783
88784             var warnings = context.validator().getIssuesBySeverity({
88785               what: 'edited',
88786               where: 'all',
88787               includeIgnored: true,
88788               includeDisabledRules: true
88789             }).warning;
88790             addIssueCounts(warnings, 'warnings'); // add counts of issues resolved by the user's edits
88791
88792             var resolvedIssues = context.validator().getResolvedIssues();
88793             addIssueCounts(resolvedIssues, 'resolved');
88794             context.changeset = context.changeset.update({
88795               tags: tags
88796             });
88797           }
88798
88799           function render(selection) {
88800             var osm = context.connection();
88801             if (!osm) return;
88802             var header = selection.selectAll('.header').data([0]);
88803             var headerTitle = header.enter().append('div').attr('class', 'header fillL');
88804             headerTitle.append('div').append('h3').html(_t.html('commit.title'));
88805             headerTitle.append('button').attr('class', 'close').on('click', function () {
88806               dispatch.call('cancel', this);
88807             }).call(svgIcon('#iD-icon-close'));
88808             var body = selection.selectAll('.body').data([0]);
88809             body = body.enter().append('div').attr('class', 'body').merge(body); // Changeset Section
88810
88811             var changesetSection = body.selectAll('.changeset-editor').data([0]);
88812             changesetSection = changesetSection.enter().append('div').attr('class', 'modal-section changeset-editor').merge(changesetSection);
88813             changesetSection.call(changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)); // Warnings
88814
88815             body.call(commitWarnings); // Upload Explanation
88816
88817             var saveSection = body.selectAll('.save-section').data([0]);
88818             saveSection = saveSection.enter().append('div').attr('class', 'modal-section save-section fillL').merge(saveSection);
88819             var prose = saveSection.selectAll('.commit-info').data([0]);
88820
88821             if (prose.enter().size()) {
88822               // first time, make sure to update user details in prose
88823               _userDetails = null;
88824             }
88825
88826             prose = prose.enter().append('p').attr('class', 'commit-info').html(_t.html('commit.upload_explanation')).merge(prose); // always check if this has changed, but only update prose.html()
88827             // if needed, because it can trigger a style recalculation
88828
88829             osm.userDetails(function (err, user) {
88830               if (err) return;
88831               if (_userDetails === user) return; // no change
88832
88833               _userDetails = user;
88834               var userLink = select(document.createElement('div'));
88835
88836               if (user.image_url) {
88837                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
88838               }
88839
88840               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
88841               prose.html(_t.html('commit.upload_explanation_with_user', {
88842                 user: userLink.html()
88843               }));
88844             }); // Request Review
88845
88846             var requestReview = saveSection.selectAll('.request-review').data([0]); // Enter
88847
88848             var requestReviewEnter = requestReview.enter().append('div').attr('class', 'request-review');
88849             var requestReviewDomId = utilUniqueDomId('commit-input-request-review');
88850             var labelEnter = requestReviewEnter.append('label').attr('for', requestReviewDomId);
88851
88852             if (!labelEnter.empty()) {
88853               labelEnter.call(uiTooltip().title(_t.html('commit.request_review_info')).placement('top'));
88854             }
88855
88856             labelEnter.append('input').attr('type', 'checkbox').attr('id', requestReviewDomId);
88857             labelEnter.append('span').html(_t.html('commit.request_review')); // Update
88858
88859             requestReview = requestReview.merge(requestReviewEnter);
88860             var requestReviewInput = requestReview.selectAll('input').property('checked', isReviewRequested(context.changeset.tags)).on('change', toggleRequestReview); // Buttons
88861
88862             var buttonSection = saveSection.selectAll('.buttons').data([0]); // enter
88863
88864             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons fillL');
88865             buttonEnter.append('button').attr('class', 'secondary-action button cancel-button').append('span').attr('class', 'label').html(_t.html('commit.cancel'));
88866             var uploadButton = buttonEnter.append('button').attr('class', 'action button save-button');
88867             uploadButton.append('span').attr('class', 'label').html(_t.html('commit.save'));
88868             var uploadBlockerTooltipText = getUploadBlockerMessage(); // update
88869
88870             buttonSection = buttonSection.merge(buttonEnter);
88871             buttonSection.selectAll('.cancel-button').on('click.cancel', function () {
88872               dispatch.call('cancel', this);
88873             });
88874             buttonSection.selectAll('.save-button').classed('disabled', uploadBlockerTooltipText !== null).on('click.save', function () {
88875               if (!select(this).classed('disabled')) {
88876                 this.blur(); // avoid keeping focus on the button - #4641
88877
88878                 for (var key in context.changeset.tags) {
88879                   // remove any empty keys before upload
88880                   if (!key) delete context.changeset.tags[key];
88881                 }
88882
88883                 context.uploader().save(context.changeset);
88884               }
88885             }); // remove any existing tooltip
88886
88887             uiTooltip().destroyAny(buttonSection.selectAll('.save-button'));
88888
88889             if (uploadBlockerTooltipText) {
88890               buttonSection.selectAll('.save-button').call(uiTooltip().title(uploadBlockerTooltipText).placement('top'));
88891             } // Raw Tag Editor
88892
88893
88894             var tagSection = body.selectAll('.tag-section.raw-tag-editor').data([0]);
88895             tagSection = tagSection.enter().append('div').attr('class', 'modal-section tag-section raw-tag-editor').merge(tagSection);
88896             tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
88897             .render);
88898             var changesSection = body.selectAll('.commit-changes-section').data([0]);
88899             changesSection = changesSection.enter().append('div').attr('class', 'modal-section commit-changes-section').merge(changesSection); // Change summary
88900
88901             changesSection.call(commitChanges.render);
88902
88903             function toggleRequestReview() {
88904               var rr = requestReviewInput.property('checked');
88905               updateChangeset({
88906                 review_requested: rr ? 'yes' : undefined
88907               });
88908               tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
88909               .render);
88910             }
88911           }
88912
88913           function getUploadBlockerMessage() {
88914             var errors = context.validator().getIssuesBySeverity({
88915               what: 'edited',
88916               where: 'all'
88917             }).error;
88918
88919             if (errors.length) {
88920               return _t('commit.outstanding_errors_message', {
88921                 count: errors.length
88922               });
88923             } else {
88924               var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
88925
88926               if (!hasChangesetComment) {
88927                 return _t('commit.comment_needed_message');
88928               }
88929             }
88930
88931             return null;
88932           }
88933
88934           function changeTags(_, changed, onInput) {
88935             if (changed.hasOwnProperty('comment')) {
88936               if (changed.comment === undefined) {
88937                 changed.comment = '';
88938               }
88939
88940               if (!onInput) {
88941                 corePreferences('comment', changed.comment);
88942                 corePreferences('commentDate', Date.now());
88943               }
88944             }
88945
88946             if (changed.hasOwnProperty('source')) {
88947               if (changed.source === undefined) {
88948                 corePreferences('source', null);
88949               } else if (!onInput) {
88950                 corePreferences('source', changed.source);
88951                 corePreferences('commentDate', Date.now());
88952               }
88953             } // no need to update `prefs` for `hashtags` here since it's done in `updateChangeset`
88954
88955
88956             updateChangeset(changed, onInput);
88957
88958             if (_selection) {
88959               _selection.call(render);
88960             }
88961           }
88962
88963           function findHashtags(tags, commentOnly) {
88964             var detectedHashtags = commentHashtags();
88965
88966             if (detectedHashtags.length) {
88967               // always remove stored hashtags if there are hashtags in the comment - #4304
88968               corePreferences('hashtags', null);
88969             }
88970
88971             if (!detectedHashtags.length || !commentOnly) {
88972               detectedHashtags = detectedHashtags.concat(hashtagHashtags());
88973             }
88974
88975             var allLowerCase = new Set();
88976             return detectedHashtags.filter(function (hashtag) {
88977               // Compare tags as lowercase strings, but keep original case tags
88978               var lowerCase = hashtag.toLowerCase();
88979
88980               if (!allLowerCase.has(lowerCase)) {
88981                 allLowerCase.add(lowerCase);
88982                 return true;
88983               }
88984
88985               return false;
88986             }); // Extract hashtags from `comment`
88987
88988             function commentHashtags() {
88989               var matches = (tags.comment || '').replace(/http\S*/g, '') // drop anything that looks like a URL - #4289
88990               .match(hashtagRegex);
88991               return matches || [];
88992             } // Extract and clean hashtags from `hashtags`
88993
88994
88995             function hashtagHashtags() {
88996               var matches = (tags.hashtags || '').split(/[,;\s]+/).map(function (s) {
88997                 if (s[0] !== '#') {
88998                   s = '#' + s;
88999                 } // prepend '#'
89000
89001
89002                 var matched = s.match(hashtagRegex);
89003                 return matched && matched[0];
89004               }).filter(Boolean); // exclude falsy
89005
89006               return matches || [];
89007             }
89008           }
89009
89010           function isReviewRequested(tags) {
89011             var rr = tags.review_requested;
89012             if (rr === undefined) return false;
89013             rr = rr.trim().toLowerCase();
89014             return !(rr === '' || rr === 'no');
89015           }
89016
89017           function updateChangeset(changed, onInput) {
89018             var tags = Object.assign({}, context.changeset.tags); // shallow copy
89019
89020             Object.keys(changed).forEach(function (k) {
89021               var v = changed[k];
89022               k = context.cleanTagKey(k);
89023               if (readOnlyTags.indexOf(k) !== -1) return;
89024
89025               if (v === undefined) {
89026                 delete tags[k];
89027               } else if (onInput) {
89028                 tags[k] = v;
89029               } else {
89030                 tags[k] = context.cleanTagValue(v);
89031               }
89032             });
89033
89034             if (!onInput) {
89035               // when changing the comment, override hashtags with any found in comment.
89036               var commentOnly = changed.hasOwnProperty('comment') && changed.comment !== '';
89037               var arr = findHashtags(tags, commentOnly);
89038
89039               if (arr.length) {
89040                 tags.hashtags = context.cleanTagValue(arr.join(';'));
89041                 corePreferences('hashtags', tags.hashtags);
89042               } else {
89043                 delete tags.hashtags;
89044                 corePreferences('hashtags', null);
89045               }
89046             } // always update userdetails, just in case user reauthenticates as someone else
89047
89048
89049             if (_userDetails && _userDetails.changesets_count !== undefined) {
89050               var changesetsCount = parseInt(_userDetails.changesets_count, 10) + 1; // #4283
89051
89052               tags.changesets_count = String(changesetsCount); // first 100 edits - new user
89053
89054               if (changesetsCount <= 100) {
89055                 var s;
89056                 s = corePreferences('walkthrough_completed');
89057
89058                 if (s) {
89059                   tags['ideditor:walkthrough_completed'] = s;
89060                 }
89061
89062                 s = corePreferences('walkthrough_progress');
89063
89064                 if (s) {
89065                   tags['ideditor:walkthrough_progress'] = s;
89066                 }
89067
89068                 s = corePreferences('walkthrough_started');
89069
89070                 if (s) {
89071                   tags['ideditor:walkthrough_started'] = s;
89072                 }
89073               }
89074             } else {
89075               delete tags.changesets_count;
89076             }
89077
89078             if (!fastDeepEqual(context.changeset.tags, tags)) {
89079               context.changeset = context.changeset.update({
89080                 tags: tags
89081               });
89082             }
89083           }
89084
89085           commit.reset = function () {
89086             context.changeset = null;
89087           };
89088
89089           return utilRebind(commit, dispatch, 'on');
89090         }
89091
89092         // for punction see https://stackoverflow.com/a/21224179
89093
89094         function simplify(str) {
89095           if (typeof str !== 'string') return '';
89096           return diacritics.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\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());
89097         }
89098
89099         // `resolveStrings`
89100         // Resolves the text strings for a given community index item
89101         //
89102         // Arguments
89103         //   `item`:  Object containing the community index item
89104         //   `defaults`: Object containing the community index default strings
89105         //   `localizerFn?`: optional function we will call to do the localization.
89106         //      This function should be like the iD `t()` function that
89107         //      accepts a `stringID` and returns a localized string
89108         //
89109         // Returns
89110         //   An Object containing all the resolved strings:
89111         //   {
89112         //     name:                     'talk-ru Mailing List',
89113         //     url:                      'https://lists.openstreetmap.org/listinfo/talk-ru',
89114         //     signupUrl:                'https://example.url/signup',
89115         //     description:              'A one line description',
89116         //     extendedDescription:      'Extended description',
89117         //     nameHTML:                 '<a href="the url">the name</a>',
89118         //     urlHTML:                  '<a href="the url">the url</a>',
89119         //     signupUrlHTML:            '<a href="the signupUrl">the signupUrl</a>',
89120         //     descriptionHTML:          the description, with urls and signupUrls linkified,
89121         //     extendedDescriptionHTML:  the extendedDescription with urls and signupUrls linkified
89122         //   }
89123         //
89124
89125         function resolveStrings(item, defaults, localizerFn) {
89126           var itemStrings = Object.assign({}, item.strings); // shallow clone
89127
89128           var defaultStrings = Object.assign({}, defaults[item.type]); // shallow clone
89129
89130           var anyToken = new RegExp(/(\{\w+\})/, 'gi'); // Pre-localize the item and default strings
89131
89132           if (localizerFn) {
89133             if (itemStrings.community) {
89134               var communityID = simplify(itemStrings.community);
89135               itemStrings.community = localizerFn("_communities.".concat(communityID));
89136             }
89137
89138             ['name', 'description', 'extendedDescription'].forEach(function (prop) {
89139               if (defaultStrings[prop]) defaultStrings[prop] = localizerFn("_defaults.".concat(item.type, ".").concat(prop));
89140               if (itemStrings[prop]) itemStrings[prop] = localizerFn("".concat(item.id, ".").concat(prop));
89141             });
89142           }
89143
89144           var replacements = {
89145             account: item.account,
89146             community: itemStrings.community,
89147             signupUrl: itemStrings.signupUrl,
89148             url: itemStrings.url
89149           }; // Resolve URLs first (which may refer to {account})
89150
89151           if (!replacements.signupUrl) {
89152             replacements.signupUrl = resolve(itemStrings.signupUrl || defaultStrings.signupUrl);
89153           }
89154
89155           if (!replacements.url) {
89156             replacements.url = resolve(itemStrings.url || defaultStrings.url);
89157           }
89158
89159           var resolved = {
89160             name: resolve(itemStrings.name || defaultStrings.name),
89161             url: resolve(itemStrings.url || defaultStrings.url),
89162             signupUrl: resolve(itemStrings.signupUrl || defaultStrings.signupUrl),
89163             description: resolve(itemStrings.description || defaultStrings.description),
89164             extendedDescription: resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription)
89165           }; // Generate linkified strings
89166
89167           resolved.nameHTML = linkify(resolved.url, resolved.name);
89168           resolved.urlHTML = linkify(resolved.url);
89169           resolved.signupUrlHTML = linkify(resolved.signupUrl);
89170           resolved.descriptionHTML = resolve(itemStrings.description || defaultStrings.description, true);
89171           resolved.extendedDescriptionHTML = resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription, true);
89172           return resolved;
89173
89174           function resolve(s, addLinks) {
89175             if (!s) return undefined;
89176             var result = s;
89177
89178             for (var key in replacements) {
89179               var token = "{".concat(key, "}");
89180               var regex = new RegExp(token, 'g');
89181
89182               if (regex.test(result)) {
89183                 var replacement = replacements[key];
89184
89185                 if (!replacement) {
89186                   throw new Error("Cannot resolve token: ".concat(token));
89187                 } else {
89188                   if (addLinks && (key === 'signupUrl' || key === 'url')) {
89189                     replacement = linkify(replacement);
89190                   }
89191
89192                   result = result.replace(regex, replacement);
89193                 }
89194               }
89195             } // There shouldn't be any leftover tokens in a resolved string
89196
89197
89198             var leftovers = result.match(anyToken);
89199
89200             if (leftovers) {
89201               throw new Error("Cannot resolve tokens: ".concat(leftovers));
89202             } // Linkify subreddits like `/r/openstreetmap`
89203             // https://github.com/osmlab/osm-community-index/issues/82
89204             // https://github.com/openstreetmap/iD/issues/4997
89205
89206
89207             if (addLinks && item.type === 'reddit') {
89208               result = result.replace(/(\/r\/\w+\/*)/i, function (match) {
89209                 return linkify(resolved.url, match);
89210               });
89211             }
89212
89213             return result;
89214           }
89215
89216           function linkify(url, text) {
89217             if (!url) return undefined;
89218             text = text || url;
89219             return "<a target=\"_blank\" href=\"".concat(url, "\">").concat(text, "</a>");
89220           }
89221         }
89222
89223         var _oci = null;
89224         function uiSuccess(context) {
89225           var MAXEVENTS = 2;
89226           var dispatch = dispatch$8('cancel');
89227
89228           var _changeset;
89229
89230           var _location;
89231
89232           ensureOSMCommunityIndex(); // start fetching the data
89233
89234           function ensureOSMCommunityIndex() {
89235             var data = _mainFileFetcher;
89236             return Promise.all([data.get('oci_features'), data.get('oci_resources'), data.get('oci_defaults')]).then(function (vals) {
89237               if (_oci) return _oci; // Merge Custom Features
89238
89239               if (vals[0] && Array.isArray(vals[0].features)) {
89240                 _mainLocations.mergeCustomGeoJSON(vals[0]);
89241               }
89242
89243               var ociResources = Object.values(vals[1].resources);
89244
89245               if (ociResources.length) {
89246                 // Resolve all locationSet features.
89247                 return _mainLocations.mergeLocationSets(ociResources).then(function () {
89248                   _oci = {
89249                     resources: ociResources,
89250                     defaults: vals[2].defaults
89251                   };
89252                   return _oci;
89253                 });
89254               } else {
89255                 _oci = {
89256                   resources: [],
89257                   // no resources?
89258                   defaults: vals[2].defaults
89259                 };
89260                 return _oci;
89261               }
89262             });
89263           } // string-to-date parsing in JavaScript is weird
89264
89265
89266           function parseEventDate(when) {
89267             if (!when) return;
89268             var raw = when.trim();
89269             if (!raw) return;
89270
89271             if (!/Z$/.test(raw)) {
89272               // if no trailing 'Z', add one
89273               raw += 'Z'; // this forces date to be parsed as a UTC date
89274             }
89275
89276             var parsed = new Date(raw);
89277             return new Date(parsed.toUTCString().substr(0, 25)); // convert to local timezone
89278           }
89279
89280           function success(selection) {
89281             var header = selection.append('div').attr('class', 'header fillL');
89282             header.append('h3').html(_t.html('success.just_edited'));
89283             header.append('button').attr('class', 'close').on('click', function () {
89284               return dispatch.call('cancel');
89285             }).call(svgIcon('#iD-icon-close'));
89286             var body = selection.append('div').attr('class', 'body save-success fillL');
89287             var summary = body.append('div').attr('class', 'save-summary');
89288             summary.append('h3').html(_t.html('success.thank_you' + (_location ? '_location' : ''), {
89289               where: _location
89290             }));
89291             summary.append('p').html(_t.html('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').html(_t.html('success.help_link_text'));
89292             var osm = context.connection();
89293             if (!osm) return;
89294             var changesetURL = osm.changesetURL(_changeset.id);
89295             var table = summary.append('table').attr('class', 'summary-table');
89296             var row = table.append('tr').attr('class', 'summary-row');
89297             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');
89298             var summaryDetail = row.append('td').attr('class', 'cell-detail summary-detail');
89299             summaryDetail.append('a').attr('class', 'cell-detail summary-view-on-osm').attr('target', '_blank').attr('href', changesetURL).html(_t.html('success.view_on_osm'));
89300             summaryDetail.append('div').html(_t.html('success.changeset_id', {
89301               changeset_id: "<a href=\"".concat(changesetURL, "\" target=\"_blank\">").concat(_changeset.id, "</a>")
89302             })); // Get OSM community index features intersecting the map..
89303
89304             ensureOSMCommunityIndex().then(function (oci) {
89305               var loc = context.map().center();
89306               var validLocations = _mainLocations.locationsAt(loc); // Gather the communities
89307
89308               var communities = [];
89309               oci.resources.forEach(function (resource) {
89310                 var area = validLocations[resource.locationSetID];
89311                 if (!area) return; // Resolve strings
89312
89313                 var localizer = function localizer(stringID) {
89314                   return _t.html("community.".concat(stringID));
89315                 };
89316
89317                 resource.resolved = resolveStrings(resource, oci.defaults, localizer);
89318                 communities.push({
89319                   area: area,
89320                   order: resource.order || 0,
89321                   resource: resource
89322                 });
89323               }); // sort communities by feature area ascending, community order descending
89324
89325               communities.sort(function (a, b) {
89326                 return a.area - b.area || b.order - a.order;
89327               });
89328               body.call(showCommunityLinks, communities.map(function (c) {
89329                 return c.resource;
89330               }));
89331             });
89332           }
89333
89334           function showCommunityLinks(selection, resources) {
89335             var communityLinks = selection.append('div').attr('class', 'save-communityLinks');
89336             communityLinks.append('h3').html(_t.html('success.like_osm'));
89337             var table = communityLinks.append('table').attr('class', 'community-table');
89338             var row = table.selectAll('.community-row').data(resources);
89339             var rowEnter = row.enter().append('tr').attr('class', 'community-row');
89340             rowEnter.append('td').attr('class', 'cell-icon community-icon').append('a').attr('target', '_blank').attr('href', function (d) {
89341               return d.resolved.url;
89342             }).append('svg').attr('class', 'logo-small').append('use').attr('xlink:href', function (d) {
89343               return "#community-".concat(d.type);
89344             });
89345             var communityDetail = rowEnter.append('td').attr('class', 'cell-detail community-detail');
89346             communityDetail.each(showCommunityDetails);
89347             communityLinks.append('div').attr('class', 'community-missing').html(_t.html('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').html(_t.html('success.tell_us'));
89348           }
89349
89350           function showCommunityDetails(d) {
89351             var selection = select(this);
89352             var communityID = d.id;
89353             selection.append('div').attr('class', 'community-name').html(d.resolved.nameHTML);
89354             selection.append('div').attr('class', 'community-description').html(d.resolved.descriptionHTML); // Create an expanding section if any of these are present..
89355
89356             if (d.resolved.extendedDescriptionHTML || d.languageCodes && d.languageCodes.length) {
89357               selection.append('div').call(uiDisclosure(context, "community-more-".concat(d.id), false).expanded(false).updatePreference(false).label(_t.html('success.more')).content(showMore));
89358             }
89359
89360             var nextEvents = (d.events || []).map(function (event) {
89361               event.date = parseEventDate(event.when);
89362               return event;
89363             }).filter(function (event) {
89364               // date is valid and future (or today)
89365               var t = event.date.getTime();
89366               var now = new Date().setHours(0, 0, 0, 0);
89367               return !isNaN(t) && t >= now;
89368             }).sort(function (a, b) {
89369               // sort by date ascending
89370               return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
89371             }).slice(0, MAXEVENTS); // limit number of events shown
89372
89373             if (nextEvents.length) {
89374               selection.append('div').call(uiDisclosure(context, "community-events-".concat(d.id), false).expanded(false).updatePreference(false).label(_t.html('success.events')).content(showNextEvents)).select('.hide-toggle').append('span').attr('class', 'badge-text').html(nextEvents.length);
89375             }
89376
89377             function showMore(selection) {
89378               var more = selection.selectAll('.community-more').data([0]);
89379               var moreEnter = more.enter().append('div').attr('class', 'community-more');
89380
89381               if (d.resolved.extendedDescriptionHTML) {
89382                 moreEnter.append('div').attr('class', 'community-extended-description').html(d.resolved.extendedDescriptionHTML);
89383               }
89384
89385               if (d.languageCodes && d.languageCodes.length) {
89386                 var languageList = d.languageCodes.map(function (code) {
89387                   return _mainLocalizer.languageName(code);
89388                 }).join(', ');
89389                 moreEnter.append('div').attr('class', 'community-languages').html(_t.html('success.languages', {
89390                   languages: languageList
89391                 }));
89392               }
89393             }
89394
89395             function showNextEvents(selection) {
89396               var events = selection.append('div').attr('class', 'community-events');
89397               var item = events.selectAll('.community-event').data(nextEvents);
89398               var itemEnter = item.enter().append('div').attr('class', 'community-event');
89399               itemEnter.append('div').attr('class', 'community-event-name').append('a').attr('target', '_blank').attr('href', function (d) {
89400                 return d.url;
89401               }).html(function (d) {
89402                 var name = d.name;
89403
89404                 if (d.i18n && d.id) {
89405                   name = _t("community.".concat(communityID, ".events.").concat(d.id, ".name"), {
89406                     "default": name
89407                   });
89408                 }
89409
89410                 return name;
89411               });
89412               itemEnter.append('div').attr('class', 'community-event-when').html(function (d) {
89413                 var options = {
89414                   weekday: 'short',
89415                   day: 'numeric',
89416                   month: 'short',
89417                   year: 'numeric'
89418                 };
89419
89420                 if (d.date.getHours() || d.date.getMinutes()) {
89421                   // include time if it has one
89422                   options.hour = 'numeric';
89423                   options.minute = 'numeric';
89424                 }
89425
89426                 return d.date.toLocaleString(_mainLocalizer.localeCode(), options);
89427               });
89428               itemEnter.append('div').attr('class', 'community-event-where').html(function (d) {
89429                 var where = d.where;
89430
89431                 if (d.i18n && d.id) {
89432                   where = _t("community.".concat(communityID, ".events.").concat(d.id, ".where"), {
89433                     "default": where
89434                   });
89435                 }
89436
89437                 return where;
89438               });
89439               itemEnter.append('div').attr('class', 'community-event-description').html(function (d) {
89440                 var description = d.description;
89441
89442                 if (d.i18n && d.id) {
89443                   description = _t("community.".concat(communityID, ".events.").concat(d.id, ".description"), {
89444                     "default": description
89445                   });
89446                 }
89447
89448                 return description;
89449               });
89450             }
89451           }
89452
89453           success.changeset = function (val) {
89454             if (!arguments.length) return _changeset;
89455             _changeset = val;
89456             return success;
89457           };
89458
89459           success.location = function (val) {
89460             if (!arguments.length) return _location;
89461             _location = val;
89462             return success;
89463           };
89464
89465           return utilRebind(success, dispatch, 'on');
89466         }
89467
89468         function modeSave(context) {
89469           var mode = {
89470             id: 'save'
89471           };
89472           var keybinding = utilKeybinding('modeSave');
89473           var commit = uiCommit(context).on('cancel', cancel);
89474
89475           var _conflictsUi; // uiConflicts
89476
89477
89478           var _location;
89479
89480           var _success;
89481
89482           var uploader = context.uploader().on('saveStarted.modeSave', function () {
89483             keybindingOff();
89484           }) // fire off some async work that we want to be ready later
89485           .on('willAttemptUpload.modeSave', prepareForSuccess).on('progressChanged.modeSave', showProgress).on('resultNoChanges.modeSave', function () {
89486             cancel();
89487           }).on('resultErrors.modeSave', showErrors).on('resultConflicts.modeSave', showConflicts).on('resultSuccess.modeSave', showSuccess);
89488
89489           function cancel() {
89490             context.enter(modeBrowse(context));
89491           }
89492
89493           function showProgress(num, total) {
89494             var modal = context.container().select('.loading-modal .modal-section');
89495             var progress = modal.selectAll('.progress').data([0]); // enter/update
89496
89497             progress.enter().append('div').attr('class', 'progress').merge(progress).text(_t('save.conflict_progress', {
89498               num: num,
89499               total: total
89500             }));
89501           }
89502
89503           function showConflicts(changeset, conflicts, origChanges) {
89504             var selection = context.container().select('.sidebar').append('div').attr('class', 'sidebar-component');
89505             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
89506             _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on('cancel', function () {
89507               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
89508               selection.remove();
89509               keybindingOn();
89510               uploader.cancelConflictResolution();
89511             }).on('save', function () {
89512               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
89513               selection.remove();
89514               uploader.processResolvedConflicts(changeset);
89515             });
89516             selection.call(_conflictsUi);
89517           }
89518
89519           function showErrors(errors) {
89520             keybindingOn();
89521             var selection = uiConfirm(context.container());
89522             selection.select('.modal-section.header').append('h3').text(_t('save.error'));
89523             addErrors(selection, errors);
89524             selection.okButton();
89525           }
89526
89527           function addErrors(selection, data) {
89528             var message = selection.select('.modal-section.message-text');
89529             var items = message.selectAll('.error-container').data(data);
89530             var enter = items.enter().append('div').attr('class', 'error-container');
89531             enter.append('a').attr('class', 'error-description').attr('href', '#').classed('hide-toggle', true).text(function (d) {
89532               return d.msg || _t('save.unknown_error_details');
89533             }).on('click', function (d3_event) {
89534               d3_event.preventDefault();
89535               var error = select(this);
89536               var detail = select(this.nextElementSibling);
89537               var exp = error.classed('expanded');
89538               detail.style('display', exp ? 'none' : 'block');
89539               error.classed('expanded', !exp);
89540             });
89541             var details = enter.append('div').attr('class', 'error-detail-container').style('display', 'none');
89542             details.append('ul').attr('class', 'error-detail-list').selectAll('li').data(function (d) {
89543               return d.details || [];
89544             }).enter().append('li').attr('class', 'error-detail-item').text(function (d) {
89545               return d;
89546             });
89547             items.exit().remove();
89548           }
89549
89550           function showSuccess(changeset) {
89551             commit.reset();
89552
89553             var ui = _success.changeset(changeset).location(_location).on('cancel', function () {
89554               context.ui().sidebar.hide();
89555             });
89556
89557             context.enter(modeBrowse(context).sidebar(ui));
89558           }
89559
89560           function keybindingOn() {
89561             select(document).call(keybinding.on('⎋', cancel, true));
89562           }
89563
89564           function keybindingOff() {
89565             select(document).call(keybinding.unbind);
89566           } // Reverse geocode current map location so we can display a message on
89567           // the success screen like "Thank you for editing around place, region."
89568
89569
89570           function prepareForSuccess() {
89571             _success = uiSuccess(context);
89572             _location = null;
89573             if (!services.geocoder) return;
89574             services.geocoder.reverse(context.map().center(), function (err, result) {
89575               if (err || !result || !result.address) return;
89576               var addr = result.address;
89577               var place = addr && (addr.town || addr.city || addr.county) || '';
89578               var region = addr && (addr.state || addr.country) || '';
89579               var separator = place && region ? _t('success.thank_you_where.separator') : '';
89580               _location = _t('success.thank_you_where.format', {
89581                 place: place,
89582                 separator: separator,
89583                 region: region
89584               });
89585             });
89586           }
89587
89588           mode.selectedIDs = function () {
89589             return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
89590           };
89591
89592           mode.enter = function () {
89593             // Show sidebar
89594             context.ui().sidebar.expand();
89595
89596             function done() {
89597               context.ui().sidebar.show(commit);
89598             }
89599
89600             keybindingOn();
89601             context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
89602             var osm = context.connection();
89603
89604             if (!osm) {
89605               cancel();
89606               return;
89607             }
89608
89609             if (osm.authenticated()) {
89610               done();
89611             } else {
89612               osm.authenticate(function (err) {
89613                 if (err) {
89614                   cancel();
89615                 } else {
89616                   done();
89617                 }
89618               });
89619             }
89620           };
89621
89622           mode.exit = function () {
89623             keybindingOff();
89624             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
89625             context.ui().sidebar.hide();
89626           };
89627
89628           return mode;
89629         }
89630
89631         function modeSelectError(context, selectedErrorID, selectedErrorService) {
89632           var mode = {
89633             id: 'select-error',
89634             button: 'browse'
89635           };
89636           var keybinding = utilKeybinding('select-error');
89637           var errorService = services[selectedErrorService];
89638           var errorEditor;
89639
89640           switch (selectedErrorService) {
89641             case 'improveOSM':
89642               errorEditor = uiImproveOsmEditor(context).on('change', function () {
89643                 context.map().pan([0, 0]); // trigger a redraw
89644
89645                 var error = checkSelectedID();
89646                 if (!error) return;
89647                 context.ui().sidebar.show(errorEditor.error(error));
89648               });
89649               break;
89650
89651             case 'keepRight':
89652               errorEditor = uiKeepRightEditor(context).on('change', function () {
89653                 context.map().pan([0, 0]); // trigger a redraw
89654
89655                 var error = checkSelectedID();
89656                 if (!error) return;
89657                 context.ui().sidebar.show(errorEditor.error(error));
89658               });
89659               break;
89660
89661             case 'osmose':
89662               errorEditor = uiOsmoseEditor(context).on('change', function () {
89663                 context.map().pan([0, 0]); // trigger a redraw
89664
89665                 var error = checkSelectedID();
89666                 if (!error) return;
89667                 context.ui().sidebar.show(errorEditor.error(error));
89668               });
89669               break;
89670           }
89671
89672           var behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
89673
89674           function checkSelectedID() {
89675             if (!errorService) return;
89676             var error = errorService.getError(selectedErrorID);
89677
89678             if (!error) {
89679               context.enter(modeBrowse(context));
89680             }
89681
89682             return error;
89683           }
89684
89685           mode.zoomToSelected = function () {
89686             if (!errorService) return;
89687             var error = errorService.getError(selectedErrorID);
89688
89689             if (error) {
89690               context.map().centerZoomEase(error.loc, 20);
89691             }
89692           };
89693
89694           mode.enter = function () {
89695             var error = checkSelectedID();
89696             if (!error) return;
89697             behaviors.forEach(context.install);
89698             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
89699             select(document).call(keybinding);
89700             selectError();
89701             var sidebar = context.ui().sidebar;
89702             sidebar.show(errorEditor.error(error));
89703             context.map().on('drawn.select-error', selectError); // class the error as selected, or return to browse mode if the error is gone
89704
89705             function selectError(d3_event, drawn) {
89706               if (!checkSelectedID()) return;
89707               var selection = context.surface().selectAll('.itemId-' + selectedErrorID + '.' + selectedErrorService);
89708
89709               if (selection.empty()) {
89710                 // Return to browse mode if selected DOM elements have
89711                 // disappeared because the user moved them out of view..
89712                 var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
89713
89714                 if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
89715                   context.enter(modeBrowse(context));
89716                 }
89717               } else {
89718                 selection.classed('selected', true);
89719                 context.selectedErrorID(selectedErrorID);
89720               }
89721             }
89722
89723             function esc() {
89724               if (context.container().select('.combobox').size()) return;
89725               context.enter(modeBrowse(context));
89726             }
89727           };
89728
89729           mode.exit = function () {
89730             behaviors.forEach(context.uninstall);
89731             select(document).call(keybinding.unbind);
89732             context.surface().selectAll('.qaItem.selected').classed('selected hover', false);
89733             context.map().on('drawn.select-error', null);
89734             context.ui().sidebar.hide();
89735             context.selectedErrorID(null);
89736             context.features().forceVisible([]);
89737           };
89738
89739           return mode;
89740         }
89741
89742         function uiToolOldDrawModes(context) {
89743           var tool = {
89744             id: 'old_modes',
89745             label: _t.html('toolbar.add_feature')
89746           };
89747           var modes = [modeAddPoint(context, {
89748             title: _t.html('modes.add_point.title'),
89749             button: 'point',
89750             description: _t.html('modes.add_point.description'),
89751             preset: _mainPresetIndex.item('point'),
89752             key: '1'
89753           }), modeAddLine(context, {
89754             title: _t.html('modes.add_line.title'),
89755             button: 'line',
89756             description: _t.html('modes.add_line.description'),
89757             preset: _mainPresetIndex.item('line'),
89758             key: '2'
89759           }), modeAddArea(context, {
89760             title: _t.html('modes.add_area.title'),
89761             button: 'area',
89762             description: _t.html('modes.add_area.description'),
89763             preset: _mainPresetIndex.item('area'),
89764             key: '3'
89765           })];
89766
89767           function enabled() {
89768             return osmEditable();
89769           }
89770
89771           function osmEditable() {
89772             return context.editable();
89773           }
89774
89775           modes.forEach(function (mode) {
89776             context.keybinding().on(mode.key, function () {
89777               if (!enabled()) return;
89778
89779               if (mode.id === context.mode().id) {
89780                 context.enter(modeBrowse(context));
89781               } else {
89782                 context.enter(mode);
89783               }
89784             });
89785           });
89786
89787           tool.render = function (selection) {
89788             var wrap = selection.append('div').attr('class', 'joined').style('display', 'flex');
89789
89790             var debouncedUpdate = debounce(update, 500, {
89791               leading: true,
89792               trailing: true
89793             });
89794
89795             context.map().on('move.modes', debouncedUpdate).on('drawn.modes', debouncedUpdate);
89796             context.on('enter.modes', update);
89797             update();
89798
89799             function update() {
89800               var buttons = wrap.selectAll('button.add-button').data(modes, function (d) {
89801                 return d.id;
89802               }); // exit
89803
89804               buttons.exit().remove(); // enter
89805
89806               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
89807                 return d.id + ' add-button bar-button';
89808               }).on('click.mode-buttons', function (d3_event, d) {
89809                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
89810
89811                 var currMode = context.mode().id;
89812                 if (/^draw/.test(currMode)) return;
89813
89814                 if (d.id === currMode) {
89815                   context.enter(modeBrowse(context));
89816                 } else {
89817                   context.enter(d);
89818                 }
89819               }).call(uiTooltip().placement('bottom').title(function (d) {
89820                 return d.description;
89821               }).keys(function (d) {
89822                 return [d.key];
89823               }).scrollContainer(context.container().select('.top-toolbar')));
89824               buttonsEnter.each(function (d) {
89825                 select(this).call(svgIcon('#iD-icon-' + d.button));
89826               });
89827               buttonsEnter.append('span').attr('class', 'label').html(function (mode) {
89828                 return mode.title;
89829               }); // if we are adding/removing the buttons, check if toolbar has overflowed
89830
89831               if (buttons.enter().size() || buttons.exit().size()) {
89832                 context.ui().checkOverflow('.top-toolbar', true);
89833               } // update
89834
89835
89836               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
89837                 return !enabled();
89838               }).classed('active', function (d) {
89839                 return context.mode() && context.mode().button === d.button;
89840               });
89841             }
89842           };
89843
89844           return tool;
89845         }
89846
89847         function uiToolNotes(context) {
89848           var tool = {
89849             id: 'notes',
89850             label: _t.html('modes.add_note.label')
89851           };
89852           var mode = modeAddNote(context);
89853
89854           function enabled() {
89855             return notesEnabled() && notesEditable();
89856           }
89857
89858           function notesEnabled() {
89859             var noteLayer = context.layers().layer('notes');
89860             return noteLayer && noteLayer.enabled();
89861           }
89862
89863           function notesEditable() {
89864             var mode = context.mode();
89865             return context.map().notesEditable() && mode && mode.id !== 'save';
89866           }
89867
89868           context.keybinding().on(mode.key, function () {
89869             if (!enabled()) return;
89870
89871             if (mode.id === context.mode().id) {
89872               context.enter(modeBrowse(context));
89873             } else {
89874               context.enter(mode);
89875             }
89876           });
89877
89878           tool.render = function (selection) {
89879             var debouncedUpdate = debounce(update, 500, {
89880               leading: true,
89881               trailing: true
89882             });
89883
89884             context.map().on('move.notes', debouncedUpdate).on('drawn.notes', debouncedUpdate);
89885             context.on('enter.notes', update);
89886             update();
89887
89888             function update() {
89889               var showNotes = notesEnabled();
89890               var data = showNotes ? [mode] : [];
89891               var buttons = selection.selectAll('button.add-button').data(data, function (d) {
89892                 return d.id;
89893               }); // exit
89894
89895               buttons.exit().remove(); // enter
89896
89897               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
89898                 return d.id + ' add-button bar-button';
89899               }).on('click.notes', function (d3_event, d) {
89900                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
89901
89902                 var currMode = context.mode().id;
89903                 if (/^draw/.test(currMode)) return;
89904
89905                 if (d.id === currMode) {
89906                   context.enter(modeBrowse(context));
89907                 } else {
89908                   context.enter(d);
89909                 }
89910               }).call(uiTooltip().placement('bottom').title(function (d) {
89911                 return d.description;
89912               }).keys(function (d) {
89913                 return [d.key];
89914               }).scrollContainer(context.container().select('.top-toolbar')));
89915               buttonsEnter.each(function (d) {
89916                 select(this).call(svgIcon(d.icon || '#iD-icon-' + d.button));
89917               }); // if we are adding/removing the buttons, check if toolbar has overflowed
89918
89919               if (buttons.enter().size() || buttons.exit().size()) {
89920                 context.ui().checkOverflow('.top-toolbar', true);
89921               } // update
89922
89923
89924               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
89925                 return !enabled();
89926               }).classed('active', function (d) {
89927                 return context.mode() && context.mode().button === d.button;
89928               });
89929             }
89930           };
89931
89932           tool.uninstall = function () {
89933             context.on('enter.editor.notes', null).on('exit.editor.notes', null).on('enter.notes', null);
89934             context.map().on('move.notes', null).on('drawn.notes', null);
89935           };
89936
89937           return tool;
89938         }
89939
89940         function uiToolSave(context) {
89941           var tool = {
89942             id: 'save',
89943             label: _t.html('save.title')
89944           };
89945           var button = null;
89946           var tooltipBehavior = null;
89947           var history = context.history();
89948           var key = uiCmd('⌘S');
89949           var _numChanges = 0;
89950
89951           function isSaving() {
89952             var mode = context.mode();
89953             return mode && mode.id === 'save';
89954           }
89955
89956           function isDisabled() {
89957             return _numChanges === 0 || isSaving();
89958           }
89959
89960           function save(d3_event) {
89961             d3_event.preventDefault();
89962
89963             if (!context.inIntro() && !isSaving() && history.hasChanges()) {
89964               context.enter(modeSave(context));
89965             }
89966           }
89967
89968           function bgColor() {
89969             var step;
89970
89971             if (_numChanges === 0) {
89972               return null;
89973             } else if (_numChanges <= 50) {
89974               step = _numChanges / 50;
89975               return d3_interpolateRgb('#fff', '#ff8')(step); // white -> yellow
89976             } else {
89977               step = Math.min((_numChanges - 50) / 50, 1.0);
89978               return d3_interpolateRgb('#ff8', '#f88')(step); // yellow -> red
89979             }
89980           }
89981
89982           function updateCount() {
89983             var val = history.difference().summary().length;
89984             if (val === _numChanges) return;
89985             _numChanges = val;
89986
89987             if (tooltipBehavior) {
89988               tooltipBehavior.title(_t.html(_numChanges > 0 ? 'save.help' : 'save.no_changes')).keys([key]);
89989             }
89990
89991             if (button) {
89992               button.classed('disabled', isDisabled()).style('background', bgColor());
89993               button.select('span.count').html(_numChanges);
89994             }
89995           }
89996
89997           tool.render = function (selection) {
89998             tooltipBehavior = uiTooltip().placement('bottom').title(_t.html('save.no_changes')).keys([key]).scrollContainer(context.container().select('.top-toolbar'));
89999             var lastPointerUpType;
90000             button = selection.append('button').attr('class', 'save disabled bar-button').on('pointerup', function (d3_event) {
90001               lastPointerUpType = d3_event.pointerType;
90002             }).on('click', function (d3_event) {
90003               save(d3_event);
90004
90005               if (_numChanges === 0 && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
90006                 // there are no tooltips for touch interactions so flash feedback instead
90007                 context.ui().flash.duration(2000).iconName('#iD-icon-save').iconClass('disabled').label(_t.html('save.no_changes'))();
90008               }
90009
90010               lastPointerUpType = null;
90011             }).call(tooltipBehavior);
90012             button.call(svgIcon('#iD-icon-save'));
90013             button.append('span').attr('class', 'count').attr('aria-hidden', 'true').html('0');
90014             updateCount();
90015             context.keybinding().on(key, save, true);
90016             context.history().on('change.save', updateCount);
90017             context.on('enter.save', function () {
90018               if (button) {
90019                 button.classed('disabled', isDisabled());
90020
90021                 if (isSaving()) {
90022                   button.call(tooltipBehavior.hide);
90023                 }
90024               }
90025             });
90026           };
90027
90028           tool.uninstall = function () {
90029             context.keybinding().off(key, true);
90030             context.history().on('change.save', null);
90031             context.on('enter.save', null);
90032             button = null;
90033             tooltipBehavior = null;
90034           };
90035
90036           return tool;
90037         }
90038
90039         function uiToolSidebarToggle(context) {
90040           var tool = {
90041             id: 'sidebar_toggle',
90042             label: _t.html('toolbar.inspect')
90043           };
90044
90045           tool.render = function (selection) {
90046             selection.append('button').attr('class', 'bar-button').on('click', function () {
90047               context.ui().sidebar.toggle();
90048             }).call(uiTooltip().placement('bottom').title(_t.html('sidebar.tooltip')).keys([_t('sidebar.key')]).scrollContainer(context.container().select('.top-toolbar'))).call(svgIcon('#iD-icon-sidebar-' + (_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')));
90049           };
90050
90051           return tool;
90052         }
90053
90054         function uiToolUndoRedo(context) {
90055           var tool = {
90056             id: 'undo_redo',
90057             label: _t.html('toolbar.undo_redo')
90058           };
90059           var commands = [{
90060             id: 'undo',
90061             cmd: uiCmd('⌘Z'),
90062             action: function action() {
90063               context.undo();
90064             },
90065             annotation: function annotation() {
90066               return context.history().undoAnnotation();
90067             },
90068             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')
90069           }, {
90070             id: 'redo',
90071             cmd: uiCmd('⌘⇧Z'),
90072             action: function action() {
90073               context.redo();
90074             },
90075             annotation: function annotation() {
90076               return context.history().redoAnnotation();
90077             },
90078             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'undo' : 'redo')
90079           }];
90080
90081           function editable() {
90082             return context.mode() && context.mode().id !== 'save' && context.map().editableDataEnabled(true
90083             /* ignore min zoom */
90084             );
90085           }
90086
90087           tool.render = function (selection) {
90088             var tooltipBehavior = uiTooltip().placement('bottom').title(function (d) {
90089               return d.annotation() ? _t.html(d.id + '.tooltip', {
90090                 action: d.annotation()
90091               }) : _t.html(d.id + '.nothing');
90092             }).keys(function (d) {
90093               return [d.cmd];
90094             }).scrollContainer(context.container().select('.top-toolbar'));
90095             var lastPointerUpType;
90096             var buttons = selection.selectAll('button').data(commands).enter().append('button').attr('class', function (d) {
90097               return 'disabled ' + d.id + '-button bar-button';
90098             }).on('pointerup', function (d3_event) {
90099               // `pointerup` is always called before `click`
90100               lastPointerUpType = d3_event.pointerType;
90101             }).on('click', function (d3_event, d) {
90102               d3_event.preventDefault();
90103               var annotation = d.annotation();
90104
90105               if (editable() && annotation) {
90106                 d.action();
90107               }
90108
90109               if (editable() && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
90110                 // there are no tooltips for touch interactions so flash feedback instead
90111                 var text = annotation ? _t(d.id + '.tooltip', {
90112                   action: annotation
90113                 }) : _t(d.id + '.nothing');
90114                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass(annotation ? '' : 'disabled').label(text)();
90115               }
90116
90117               lastPointerUpType = null;
90118             }).call(tooltipBehavior);
90119             buttons.each(function (d) {
90120               select(this).call(svgIcon('#' + d.icon));
90121             });
90122             context.keybinding().on(commands[0].cmd, function (d3_event) {
90123               d3_event.preventDefault();
90124               if (editable()) commands[0].action();
90125             }).on(commands[1].cmd, function (d3_event) {
90126               d3_event.preventDefault();
90127               if (editable()) commands[1].action();
90128             });
90129
90130             var debouncedUpdate = debounce(update, 500, {
90131               leading: true,
90132               trailing: true
90133             });
90134
90135             context.map().on('move.undo_redo', debouncedUpdate).on('drawn.undo_redo', debouncedUpdate);
90136             context.history().on('change.undo_redo', function (difference) {
90137               if (difference) update();
90138             });
90139             context.on('enter.undo_redo', update);
90140
90141             function update() {
90142               buttons.classed('disabled', function (d) {
90143                 return !editable() || !d.annotation();
90144               }).each(function () {
90145                 var selection = select(this);
90146
90147                 if (!selection.select('.tooltip.in').empty()) {
90148                   selection.call(tooltipBehavior.updateContent);
90149                 }
90150               });
90151             }
90152           };
90153
90154           tool.uninstall = function () {
90155             context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
90156             context.map().on('move.undo_redo', null).on('drawn.undo_redo', null);
90157             context.history().on('change.undo_redo', null);
90158             context.on('enter.undo_redo', null);
90159           };
90160
90161           return tool;
90162         }
90163
90164         function uiTopToolbar(context) {
90165           var sidebarToggle = uiToolSidebarToggle(context),
90166               modes = uiToolOldDrawModes(context),
90167               notes = uiToolNotes(context),
90168               undoRedo = uiToolUndoRedo(context),
90169               save = uiToolSave(context);
90170
90171           function notesEnabled() {
90172             var noteLayer = context.layers().layer('notes');
90173             return noteLayer && noteLayer.enabled();
90174           }
90175
90176           function topToolbar(bar) {
90177             bar.on('wheel.topToolbar', function (d3_event) {
90178               if (!d3_event.deltaX) {
90179                 // translate vertical scrolling into horizontal scrolling in case
90180                 // the user doesn't have an input device that can scroll horizontally
90181                 bar.node().scrollLeft += d3_event.deltaY;
90182               }
90183             });
90184
90185             var debouncedUpdate = debounce(update, 500, {
90186               leading: true,
90187               trailing: true
90188             });
90189
90190             context.layers().on('change.topToolbar', debouncedUpdate);
90191             update();
90192
90193             function update() {
90194               var tools = [sidebarToggle, 'spacer', modes];
90195               tools.push('spacer');
90196
90197               if (notesEnabled()) {
90198                 tools = tools.concat([notes, 'spacer']);
90199               }
90200
90201               tools = tools.concat([undoRedo, save]);
90202               var toolbarItems = bar.selectAll('.toolbar-item').data(tools, function (d) {
90203                 return d.id || d;
90204               });
90205               toolbarItems.exit().each(function (d) {
90206                 if (d.uninstall) {
90207                   d.uninstall();
90208                 }
90209               }).remove();
90210               var itemsEnter = toolbarItems.enter().append('div').attr('class', function (d) {
90211                 var classes = 'toolbar-item ' + (d.id || d).replace('_', '-');
90212                 if (d.klass) classes += ' ' + d.klass;
90213                 return classes;
90214               });
90215               var actionableItems = itemsEnter.filter(function (d) {
90216                 return d !== 'spacer';
90217               });
90218               actionableItems.append('div').attr('class', 'item-content').each(function (d) {
90219                 select(this).call(d.render, bar);
90220               });
90221               actionableItems.append('div').attr('class', 'item-label').html(function (d) {
90222                 return d.label;
90223               });
90224             }
90225           }
90226
90227           return topToolbar;
90228         }
90229
90230         var sawVersion = null;
90231         var isNewVersion = false;
90232         var isNewUser = false;
90233         function uiVersion(context) {
90234           var currVersion = context.version;
90235           var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
90236
90237           if (sawVersion === null && matchedVersion !== null) {
90238             if (corePreferences('sawVersion')) {
90239               isNewUser = false;
90240               isNewVersion = corePreferences('sawVersion') !== currVersion && currVersion.indexOf('-') === -1;
90241             } else {
90242               isNewUser = true;
90243               isNewVersion = true;
90244             }
90245
90246             corePreferences('sawVersion', currVersion);
90247             sawVersion = currVersion;
90248           }
90249
90250           return function (selection) {
90251             selection.append('a').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD').html(currVersion); // only show new version indicator to users that have used iD before
90252
90253             if (isNewVersion && !isNewUser) {
90254               selection.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-11')).call(uiTooltip().title(_t.html('version.whats_new', {
90255                 version: currVersion
90256               })).placement('top').scrollContainer(context.container().select('.main-footer-wrap')));
90257             }
90258           };
90259         }
90260
90261         function uiZoom(context) {
90262           var zooms = [{
90263             id: 'zoom-in',
90264             icon: 'iD-icon-plus',
90265             title: _t.html('zoom.in'),
90266             action: zoomIn,
90267             disabled: function disabled() {
90268               return !context.map().canZoomIn();
90269             },
90270             disabledTitle: _t.html('zoom.disabled.in'),
90271             key: '+'
90272           }, {
90273             id: 'zoom-out',
90274             icon: 'iD-icon-minus',
90275             title: _t.html('zoom.out'),
90276             action: zoomOut,
90277             disabled: function disabled() {
90278               return !context.map().canZoomOut();
90279             },
90280             disabledTitle: _t.html('zoom.disabled.out'),
90281             key: '-'
90282           }];
90283
90284           function zoomIn(d3_event) {
90285             if (d3_event.shiftKey) return;
90286             d3_event.preventDefault();
90287             context.map().zoomIn();
90288           }
90289
90290           function zoomOut(d3_event) {
90291             if (d3_event.shiftKey) return;
90292             d3_event.preventDefault();
90293             context.map().zoomOut();
90294           }
90295
90296           function zoomInFurther(d3_event) {
90297             if (d3_event.shiftKey) return;
90298             d3_event.preventDefault();
90299             context.map().zoomInFurther();
90300           }
90301
90302           function zoomOutFurther(d3_event) {
90303             if (d3_event.shiftKey) return;
90304             d3_event.preventDefault();
90305             context.map().zoomOutFurther();
90306           }
90307
90308           return function (selection) {
90309             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function (d) {
90310               if (d.disabled()) {
90311                 return d.disabledTitle;
90312               }
90313
90314               return d.title;
90315             }).keys(function (d) {
90316               return [d.key];
90317             });
90318             var lastPointerUpType;
90319             var buttons = selection.selectAll('button').data(zooms).enter().append('button').attr('class', function (d) {
90320               return d.id;
90321             }).on('pointerup.editor', function (d3_event) {
90322               lastPointerUpType = d3_event.pointerType;
90323             }).on('click.editor', function (d3_event, d) {
90324               if (!d.disabled()) {
90325                 d.action(d3_event);
90326               } else if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
90327                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass('disabled').label(d.disabledTitle)();
90328               }
90329
90330               lastPointerUpType = null;
90331             }).call(tooltipBehavior);
90332             buttons.each(function (d) {
90333               select(this).call(svgIcon('#' + d.icon, 'light'));
90334             });
90335             utilKeybinding.plusKeys.forEach(function (key) {
90336               context.keybinding().on([key], zoomIn);
90337               context.keybinding().on([uiCmd('⌥' + key)], zoomInFurther);
90338             });
90339             utilKeybinding.minusKeys.forEach(function (key) {
90340               context.keybinding().on([key], zoomOut);
90341               context.keybinding().on([uiCmd('⌥' + key)], zoomOutFurther);
90342             });
90343
90344             function updateButtonStates() {
90345               buttons.classed('disabled', function (d) {
90346                 return d.disabled();
90347               }).each(function () {
90348                 var selection = select(this);
90349
90350                 if (!selection.select('.tooltip.in').empty()) {
90351                   selection.call(tooltipBehavior.updateContent);
90352                 }
90353               });
90354             }
90355
90356             updateButtonStates();
90357             context.map().on('move.uiZoom', updateButtonStates);
90358           };
90359         }
90360
90361         function uiZoomToSelection(context) {
90362           function isDisabled() {
90363             var mode = context.mode();
90364             return !mode || !mode.zoomToSelected;
90365           }
90366
90367           var _lastPointerUpType;
90368
90369           function pointerup(d3_event) {
90370             _lastPointerUpType = d3_event.pointerType;
90371           }
90372
90373           function click(d3_event) {
90374             d3_event.preventDefault();
90375
90376             if (isDisabled()) {
90377               if (_lastPointerUpType === 'touch' || _lastPointerUpType === 'pen') {
90378                 context.ui().flash.duration(2000).iconName('#iD-icon-framed-dot').iconClass('disabled').label(_t.html('inspector.zoom_to.no_selection'))();
90379               }
90380             } else {
90381               var mode = context.mode();
90382
90383               if (mode && mode.zoomToSelected) {
90384                 mode.zoomToSelected();
90385               }
90386             }
90387
90388             _lastPointerUpType = null;
90389           }
90390
90391           return function (selection) {
90392             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function () {
90393               if (isDisabled()) {
90394                 return _t.html('inspector.zoom_to.no_selection');
90395               }
90396
90397               return _t.html('inspector.zoom_to.title');
90398             }).keys([_t('inspector.zoom_to.key')]);
90399             var button = selection.append('button').on('pointerup', pointerup).on('click', click).call(svgIcon('#iD-icon-framed-dot', 'light')).call(tooltipBehavior);
90400
90401             function setEnabledState() {
90402               button.classed('disabled', isDisabled());
90403
90404               if (!button.select('.tooltip.in').empty()) {
90405                 button.call(tooltipBehavior.updateContent);
90406               }
90407             }
90408
90409             context.on('enter.uiZoomToSelection', setEnabledState);
90410             setEnabledState();
90411           };
90412         }
90413
90414         function uiPane(id, context) {
90415           var _key;
90416
90417           var _label = '';
90418           var _description = '';
90419           var _iconName = '';
90420
90421           var _sections; // array of uiSection objects
90422
90423
90424           var _paneSelection = select(null);
90425
90426           var _paneTooltip;
90427
90428           var pane = {
90429             id: id
90430           };
90431
90432           pane.label = function (val) {
90433             if (!arguments.length) return _label;
90434             _label = val;
90435             return pane;
90436           };
90437
90438           pane.key = function (val) {
90439             if (!arguments.length) return _key;
90440             _key = val;
90441             return pane;
90442           };
90443
90444           pane.description = function (val) {
90445             if (!arguments.length) return _description;
90446             _description = val;
90447             return pane;
90448           };
90449
90450           pane.iconName = function (val) {
90451             if (!arguments.length) return _iconName;
90452             _iconName = val;
90453             return pane;
90454           };
90455
90456           pane.sections = function (val) {
90457             if (!arguments.length) return _sections;
90458             _sections = val;
90459             return pane;
90460           };
90461
90462           pane.selection = function () {
90463             return _paneSelection;
90464           };
90465
90466           function hidePane() {
90467             context.ui().togglePanes();
90468           }
90469
90470           pane.togglePane = function (d3_event) {
90471             if (d3_event) d3_event.preventDefault();
90472
90473             _paneTooltip.hide();
90474
90475             context.ui().togglePanes(!_paneSelection.classed('shown') ? _paneSelection : undefined);
90476           };
90477
90478           pane.renderToggleButton = function (selection) {
90479             if (!_paneTooltip) {
90480               _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(_description).keys([_key]);
90481             }
90482
90483             selection.append('button').on('click', pane.togglePane).call(svgIcon('#' + _iconName, 'light')).call(_paneTooltip);
90484           };
90485
90486           pane.renderContent = function (selection) {
90487             // override to fully customize content
90488             if (_sections) {
90489               _sections.forEach(function (section) {
90490                 selection.call(section.render);
90491               });
90492             }
90493           };
90494
90495           pane.renderPane = function (selection) {
90496             _paneSelection = selection.append('div').attr('class', 'fillL map-pane hide ' + id + '-pane').attr('pane', id);
90497
90498             var heading = _paneSelection.append('div').attr('class', 'pane-heading');
90499
90500             heading.append('h2').html(_label);
90501             heading.append('button').on('click', hidePane).call(svgIcon('#iD-icon-close'));
90502
90503             _paneSelection.append('div').attr('class', 'pane-content').call(pane.renderContent);
90504
90505             if (_key) {
90506               context.keybinding().on(_key, pane.togglePane);
90507             }
90508           };
90509
90510           return pane;
90511         }
90512
90513         function uiSectionBackgroundDisplayOptions(context) {
90514           var section = uiSection('background-display-options', context).label(_t.html('background.display_options')).disclosureContent(renderDisclosureContent);
90515
90516           var _detected = utilDetect();
90517
90518           var _storedOpacity = corePreferences('background-opacity');
90519
90520           var _minVal = 0;
90521
90522           var _maxVal = _detected.cssfilters ? 3 : 1;
90523
90524           var _sliders = _detected.cssfilters ? ['brightness', 'contrast', 'saturation', 'sharpness'] : ['brightness'];
90525
90526           var _options = {
90527             brightness: _storedOpacity !== null ? +_storedOpacity : 1,
90528             contrast: 1,
90529             saturation: 1,
90530             sharpness: 1
90531           };
90532
90533           function clamp(x, min, max) {
90534             return Math.max(min, Math.min(x, max));
90535           }
90536
90537           function updateValue(d, val) {
90538             val = clamp(val, _minVal, _maxVal);
90539             _options[d] = val;
90540             context.background()[d](val);
90541
90542             if (d === 'brightness') {
90543               corePreferences('background-opacity', val);
90544             }
90545
90546             section.reRender();
90547           }
90548
90549           function renderDisclosureContent(selection) {
90550             var container = selection.selectAll('.display-options-container').data([0]);
90551             var containerEnter = container.enter().append('div').attr('class', 'display-options-container controls-list'); // add slider controls
90552
90553             var slidersEnter = containerEnter.selectAll('.display-control').data(_sliders).enter().append('div').attr('class', function (d) {
90554               return 'display-control display-control-' + d;
90555             });
90556             slidersEnter.append('h5').html(function (d) {
90557               return _t.html('background.' + d);
90558             }).append('span').attr('class', function (d) {
90559               return 'display-option-value display-option-value-' + d;
90560             });
90561             var sildersControlEnter = slidersEnter.append('div').attr('class', 'control-wrap');
90562             sildersControlEnter.append('input').attr('class', function (d) {
90563               return 'display-option-input display-option-input-' + d;
90564             }).attr('type', 'range').attr('min', _minVal).attr('max', _maxVal).attr('step', '0.05').on('input', function (d3_event, d) {
90565               var val = select(this).property('value');
90566
90567               if (!val && d3_event && d3_event.target) {
90568                 val = d3_event.target.value;
90569               }
90570
90571               updateValue(d, val);
90572             });
90573             sildersControlEnter.append('button').attr('title', _t('background.reset')).attr('class', function (d) {
90574               return 'display-option-reset display-option-reset-' + d;
90575             }).on('click', function (d3_event, d) {
90576               if (d3_event.button !== 0) return;
90577               updateValue(d, 1);
90578             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo'))); // reset all button
90579
90580             containerEnter.append('a').attr('class', 'display-option-resetlink').attr('href', '#').html(_t.html('background.reset_all')).on('click', function (d3_event) {
90581               d3_event.preventDefault();
90582
90583               for (var i = 0; i < _sliders.length; i++) {
90584                 updateValue(_sliders[i], 1);
90585               }
90586             }); // update
90587
90588             container = containerEnter.merge(container);
90589             container.selectAll('.display-option-input').property('value', function (d) {
90590               return _options[d];
90591             });
90592             container.selectAll('.display-option-value').html(function (d) {
90593               return Math.floor(_options[d] * 100) + '%';
90594             });
90595             container.selectAll('.display-option-reset').classed('disabled', function (d) {
90596               return _options[d] === 1;
90597             }); // first time only, set brightness if needed
90598
90599             if (containerEnter.size() && _options.brightness !== 1) {
90600               context.background().brightness(_options.brightness);
90601             }
90602           }
90603
90604           return section;
90605         }
90606
90607         function uiSettingsCustomBackground() {
90608           var dispatch = dispatch$8('change');
90609
90610           function render(selection) {
90611             // keep separate copies of original and current settings
90612             var _origSettings = {
90613               template: corePreferences('background-custom-template')
90614             };
90615             var _currSettings = {
90616               template: corePreferences('background-custom-template')
90617             };
90618             var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
90619             var modal = uiConfirm(selection).okButton();
90620             modal.classed('settings-modal settings-custom-background', true);
90621             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_background.header'));
90622             var textSection = modal.select('.modal-section.message-text');
90623             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, "`");
90624             textSection.append('div').attr('class', 'instructions-template').html(marked_1(instructions));
90625             textSection.append('textarea').attr('class', 'field-template').attr('placeholder', _t('settings.custom_background.template.placeholder')).call(utilNoAuto).property('value', _currSettings.template); // insert a cancel button
90626
90627             var buttonSection = modal.select('.modal-section.buttons');
90628             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
90629             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
90630             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
90631
90632             function isSaveDisabled() {
90633               return null;
90634             } // restore the original template
90635
90636
90637             function clickCancel() {
90638               textSection.select('.field-template').property('value', _origSettings.template);
90639               corePreferences('background-custom-template', _origSettings.template);
90640               this.blur();
90641               modal.close();
90642             } // accept the current template
90643
90644
90645             function clickSave() {
90646               _currSettings.template = textSection.select('.field-template').property('value');
90647               corePreferences('background-custom-template', _currSettings.template);
90648               this.blur();
90649               modal.close();
90650               dispatch.call('change', this, _currSettings);
90651             }
90652           }
90653
90654           return utilRebind(render, dispatch, 'on');
90655         }
90656
90657         function uiSectionBackgroundList(context) {
90658           var _backgroundList = select(null);
90659
90660           var _customSource = context.background().findSource('custom');
90661
90662           var _settingsCustomBackground = uiSettingsCustomBackground().on('change', customChanged);
90663
90664           var section = uiSection('background-list', context).label(_t.html('background.backgrounds')).disclosureContent(renderDisclosureContent);
90665
90666           function previousBackgroundID() {
90667             return corePreferences('background-last-used-toggle');
90668           }
90669
90670           function renderDisclosureContent(selection) {
90671             // the background list
90672             var container = selection.selectAll('.layer-background-list').data([0]);
90673             _backgroundList = container.enter().append('ul').attr('class', 'layer-list layer-background-list').attr('dir', 'auto').merge(container); // add minimap toggle below list
90674
90675             var bgExtrasListEnter = selection.selectAll('.bg-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list bg-extras-list');
90676             var minimapLabelEnter = bgExtrasListEnter.append('li').attr('class', 'minimap-toggle-item').append('label').call(uiTooltip().title(_t.html('background.minimap.tooltip')).keys([_t('background.minimap.key')]).placement('top'));
90677             minimapLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
90678               d3_event.preventDefault();
90679               uiMapInMap.toggle();
90680             });
90681             minimapLabelEnter.append('span').html(_t.html('background.minimap.description'));
90682             var panelLabelEnter = bgExtrasListEnter.append('li').attr('class', 'background-panel-toggle-item').append('label').call(uiTooltip().title(_t.html('background.panel.tooltip')).keys([uiCmd('⌘⇧' + _t('info_panels.background.key'))]).placement('top'));
90683             panelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
90684               d3_event.preventDefault();
90685               context.ui().info.toggle('background');
90686             });
90687             panelLabelEnter.append('span').html(_t.html('background.panel.description'));
90688             var locPanelLabelEnter = bgExtrasListEnter.append('li').attr('class', 'location-panel-toggle-item').append('label').call(uiTooltip().title(_t.html('background.location_panel.tooltip')).keys([uiCmd('⌘⇧' + _t('info_panels.location.key'))]).placement('top'));
90689             locPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
90690               d3_event.preventDefault();
90691               context.ui().info.toggle('location');
90692             });
90693             locPanelLabelEnter.append('span').html(_t.html('background.location_panel.description')); // "Info / Report a Problem" link
90694
90695             selection.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').html(_t.html('background.imagery_problem_faq'));
90696
90697             _backgroundList.call(drawListItems, 'radio', function (d3_event, d) {
90698               chooseBackground(d);
90699             }, function (d) {
90700               return !d.isHidden() && !d.overlay;
90701             });
90702           }
90703
90704           function setTooltips(selection) {
90705             selection.each(function (d, i, nodes) {
90706               var item = select(this).select('label');
90707               var span = item.select('span');
90708               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
90709               var description = d.description();
90710               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
90711               item.call(uiTooltip().destroyAny);
90712
90713               if (d.id === previousBackgroundID()) {
90714                 item.call(uiTooltip().placement(placement).title('<div>' + _t.html('background.switch') + '</div>').keys([uiCmd('⌘' + _t('background.key'))]));
90715               } else if (description || isOverflowing) {
90716                 item.call(uiTooltip().placement(placement).title(description || d.label()));
90717               }
90718             });
90719           }
90720
90721           function drawListItems(layerList, type, change, filter) {
90722             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter).sort(function (a, b) {
90723               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
90724             });
90725             var layerLinks = layerList.selectAll('li') // We have to be a bit inefficient about reordering the list since
90726             // arrow key navigation of radio values likes to work in the order
90727             // they were added, not the display document order.
90728             .data(sources, function (d, i) {
90729               return d.id + '---' + i;
90730             });
90731             layerLinks.exit().remove();
90732             var enter = layerLinks.enter().append('li').classed('layer-custom', function (d) {
90733               return d.id === 'custom';
90734             }).classed('best', function (d) {
90735               return d.best();
90736             });
90737             var label = enter.append('label');
90738             label.append('input').attr('type', type).attr('name', 'background-layer').attr('value', function (d) {
90739               return d.id;
90740             }).on('change', change);
90741             label.append('span').html(function (d) {
90742               return d.label();
90743             });
90744             enter.filter(function (d) {
90745               return d.id === 'custom';
90746             }).append('button').attr('class', 'layer-browse').call(uiTooltip().title(_t.html('settings.custom_background.tooltip')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).on('click', function (d3_event) {
90747               d3_event.preventDefault();
90748               editCustom();
90749             }).call(svgIcon('#iD-icon-more'));
90750             enter.filter(function (d) {
90751               return d.best();
90752             }).append('div').attr('class', 'best').call(uiTooltip().title(_t.html('background.best_imagery')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).append('span').html('&#9733;');
90753             layerList.call(updateLayerSelections);
90754           }
90755
90756           function updateLayerSelections(selection) {
90757             function active(d) {
90758               return context.background().showsLayer(d);
90759             }
90760
90761             selection.selectAll('li').classed('active', active).classed('switch', function (d) {
90762               return d.id === previousBackgroundID();
90763             }).call(setTooltips).selectAll('input').property('checked', active);
90764           }
90765
90766           function chooseBackground(d) {
90767             if (d.id === 'custom' && !d.template()) {
90768               return editCustom();
90769             }
90770
90771             var previousBackground = context.background().baseLayerSource();
90772             corePreferences('background-last-used-toggle', previousBackground.id);
90773             corePreferences('background-last-used', d.id);
90774             context.background().baseLayerSource(d);
90775           }
90776
90777           function customChanged(d) {
90778             if (d && d.template) {
90779               _customSource.template(d.template);
90780
90781               chooseBackground(_customSource);
90782             } else {
90783               _customSource.template('');
90784
90785               chooseBackground(context.background().findSource('none'));
90786             }
90787           }
90788
90789           function editCustom() {
90790             context.container().call(_settingsCustomBackground);
90791           }
90792
90793           context.background().on('change.background_list', function () {
90794             _backgroundList.call(updateLayerSelections);
90795           });
90796           context.map().on('move.background_list', debounce(function () {
90797             // layers in-view may have changed due to map move
90798             window.requestIdleCallback(section.reRender);
90799           }, 1000));
90800           return section;
90801         }
90802
90803         function uiSectionBackgroundOffset(context) {
90804           var section = uiSection('background-offset', context).label(_t.html('background.fix_misalignment')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
90805
90806           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
90807
90808           var _directions = [['top', [0, -0.5]], ['left', [-0.5, 0]], ['right', [0.5, 0]], ['bottom', [0, 0.5]]];
90809
90810           function updateValue() {
90811             var meters = geoOffsetToMeters(context.background().offset());
90812             var x = +meters[0].toFixed(2);
90813             var y = +meters[1].toFixed(2);
90814             context.container().selectAll('.nudge-inner-rect').select('input').classed('error', false).property('value', x + ', ' + y);
90815             context.container().selectAll('.nudge-reset').classed('disabled', function () {
90816               return x === 0 && y === 0;
90817             });
90818           }
90819
90820           function resetOffset() {
90821             context.background().offset([0, 0]);
90822             updateValue();
90823           }
90824
90825           function nudge(d) {
90826             context.background().nudge(d, context.map().zoom());
90827             updateValue();
90828           }
90829
90830           function inputOffset() {
90831             var input = select(this);
90832             var d = input.node().value;
90833             if (d === '') return resetOffset();
90834             d = d.replace(/;/g, ',').split(',').map(function (n) {
90835               // if n is NaN, it will always get mapped to false.
90836               return !isNaN(n) && n;
90837             });
90838
90839             if (d.length !== 2 || !d[0] || !d[1]) {
90840               input.classed('error', true);
90841               return;
90842             }
90843
90844             context.background().offset(geoMetersToOffset(d));
90845             updateValue();
90846           }
90847
90848           function dragOffset(d3_event) {
90849             if (d3_event.button !== 0) return;
90850             var origin = [d3_event.clientX, d3_event.clientY];
90851             var pointerId = d3_event.pointerId || 'mouse';
90852             context.container().append('div').attr('class', 'nudge-surface');
90853             select(window).on(_pointerPrefix + 'move.drag-bg-offset', pointermove).on(_pointerPrefix + 'up.drag-bg-offset', pointerup);
90854
90855             if (_pointerPrefix === 'pointer') {
90856               select(window).on('pointercancel.drag-bg-offset', pointerup);
90857             }
90858
90859             function pointermove(d3_event) {
90860               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
90861               var latest = [d3_event.clientX, d3_event.clientY];
90862               var d = [-(origin[0] - latest[0]) / 4, -(origin[1] - latest[1]) / 4];
90863               origin = latest;
90864               nudge(d);
90865             }
90866
90867             function pointerup(d3_event) {
90868               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
90869               if (d3_event.button !== 0) return;
90870               context.container().selectAll('.nudge-surface').remove();
90871               select(window).on('.drag-bg-offset', null);
90872             }
90873           }
90874
90875           function renderDisclosureContent(selection) {
90876             var container = selection.selectAll('.nudge-container').data([0]);
90877             var containerEnter = container.enter().append('div').attr('class', 'nudge-container');
90878             containerEnter.append('div').attr('class', 'nudge-instructions').html(_t.html('background.offset'));
90879             var nudgeWrapEnter = containerEnter.append('div').attr('class', 'nudge-controls-wrap');
90880             var nudgeEnter = nudgeWrapEnter.append('div').attr('class', 'nudge-outer-rect').on(_pointerPrefix + 'down', dragOffset);
90881             nudgeEnter.append('div').attr('class', 'nudge-inner-rect').append('input').attr('type', 'text').on('change', inputOffset);
90882             nudgeWrapEnter.append('div').selectAll('button').data(_directions).enter().append('button').attr('class', function (d) {
90883               return d[0] + ' nudge';
90884             }).on('click', function (d3_event, d) {
90885               nudge(d[1]);
90886             });
90887             nudgeWrapEnter.append('button').attr('title', _t('background.reset')).attr('class', 'nudge-reset disabled').on('click', function (d3_event) {
90888               d3_event.preventDefault();
90889               resetOffset();
90890             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')));
90891             updateValue();
90892           }
90893
90894           context.background().on('change.backgroundOffset-update', updateValue);
90895           return section;
90896         }
90897
90898         function uiSectionOverlayList(context) {
90899           var section = uiSection('overlay-list', context).label(_t.html('background.overlays')).disclosureContent(renderDisclosureContent);
90900
90901           var _overlayList = select(null);
90902
90903           function setTooltips(selection) {
90904             selection.each(function (d, i, nodes) {
90905               var item = select(this).select('label');
90906               var span = item.select('span');
90907               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
90908               var description = d.description();
90909               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
90910               item.call(uiTooltip().destroyAny);
90911
90912               if (description || isOverflowing) {
90913                 item.call(uiTooltip().placement(placement).title(description || d.name()));
90914               }
90915             });
90916           }
90917
90918           function updateLayerSelections(selection) {
90919             function active(d) {
90920               return context.background().showsLayer(d);
90921             }
90922
90923             selection.selectAll('li').classed('active', active).call(setTooltips).selectAll('input').property('checked', active);
90924           }
90925
90926           function chooseOverlay(d3_event, d) {
90927             d3_event.preventDefault();
90928             context.background().toggleOverlayLayer(d);
90929
90930             _overlayList.call(updateLayerSelections);
90931
90932             document.activeElement.blur();
90933           }
90934
90935           function drawListItems(layerList, type, change, filter) {
90936             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter);
90937             var layerLinks = layerList.selectAll('li').data(sources, function (d) {
90938               return d.name();
90939             });
90940             layerLinks.exit().remove();
90941             var enter = layerLinks.enter().append('li');
90942             var label = enter.append('label');
90943             label.append('input').attr('type', type).attr('name', 'layers').on('change', change);
90944             label.append('span').html(function (d) {
90945               return d.label();
90946             });
90947             layerList.selectAll('li').sort(sortSources);
90948             layerList.call(updateLayerSelections);
90949
90950             function sortSources(a, b) {
90951               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
90952             }
90953           }
90954
90955           function renderDisclosureContent(selection) {
90956             var container = selection.selectAll('.layer-overlay-list').data([0]);
90957             _overlayList = container.enter().append('ul').attr('class', 'layer-list layer-overlay-list').attr('dir', 'auto').merge(container);
90958
90959             _overlayList.call(drawListItems, 'checkbox', chooseOverlay, function (d) {
90960               return !d.isHidden() && d.overlay;
90961             });
90962           }
90963
90964           context.map().on('move.overlay_list', debounce(function () {
90965             // layers in-view may have changed due to map move
90966             window.requestIdleCallback(section.reRender);
90967           }, 1000));
90968           return section;
90969         }
90970
90971         function uiPaneBackground(context) {
90972           var backgroundPane = uiPane('background', context).key(_t('background.key')).label(_t.html('background.title')).description(_t.html('background.description')).iconName('iD-icon-layers').sections([uiSectionBackgroundList(context), uiSectionOverlayList(context), uiSectionBackgroundDisplayOptions(context), uiSectionBackgroundOffset(context)]);
90973           return backgroundPane;
90974         }
90975
90976         function uiPaneHelp(context) {
90977           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']]];
90978           var headings = {
90979             'help.help.open_data_h': 3,
90980             'help.help.before_start_h': 3,
90981             'help.help.open_source_h': 3,
90982             'help.overview.navigation_h': 3,
90983             'help.overview.features_h': 3,
90984             'help.editing.select_h': 3,
90985             'help.editing.multiselect_h': 3,
90986             'help.editing.undo_redo_h': 3,
90987             'help.editing.save_h': 3,
90988             'help.editing.upload_h': 3,
90989             'help.editing.backups_h': 3,
90990             'help.editing.keyboard_h': 3,
90991             'help.feature_editor.type_h': 3,
90992             'help.feature_editor.fields_h': 3,
90993             'help.feature_editor.tags_h': 3,
90994             'help.points.add_point_h': 3,
90995             'help.points.move_point_h': 3,
90996             'help.points.delete_point_h': 3,
90997             'help.lines.add_line_h': 3,
90998             'help.lines.modify_line_h': 3,
90999             'help.lines.connect_line_h': 3,
91000             'help.lines.disconnect_line_h': 3,
91001             'help.lines.move_line_h': 3,
91002             'help.lines.delete_line_h': 3,
91003             'help.areas.point_or_area_h': 3,
91004             'help.areas.add_area_h': 3,
91005             'help.areas.square_area_h': 3,
91006             'help.areas.modify_area_h': 3,
91007             'help.areas.delete_area_h': 3,
91008             'help.relations.edit_relation_h': 3,
91009             'help.relations.maintain_relation_h': 3,
91010             'help.relations.relation_types_h': 2,
91011             'help.relations.multipolygon_h': 3,
91012             'help.relations.turn_restriction_h': 3,
91013             'help.relations.route_h': 3,
91014             'help.relations.boundary_h': 3,
91015             'help.notes.add_note_h': 3,
91016             'help.notes.update_note_h': 3,
91017             'help.notes.save_note_h': 3,
91018             'help.imagery.sources_h': 3,
91019             'help.imagery.offsets_h': 3,
91020             'help.streetlevel.using_h': 3,
91021             'help.gps.using_h': 3,
91022             'help.qa.tools_h': 3,
91023             'help.qa.issues_h': 3
91024           }; // For each section, squash all the texts into a single markdown document
91025
91026           var docs = docKeys.map(function (key) {
91027             var helpkey = 'help.' + key[0];
91028             var helpPaneReplacements = {
91029               version: context.version
91030             };
91031             var text = key[1].reduce(function (all, part) {
91032               var subkey = helpkey + '.' + part;
91033               var depth = headings[subkey]; // is this subkey a heading?
91034
91035               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
91036
91037               return all + hhh + helpHtml(subkey, helpPaneReplacements) + '\n\n';
91038             }, '');
91039             return {
91040               title: _t.html(helpkey + '.title'),
91041               content: marked_1(text.trim()) // use keyboard key styling for shortcuts
91042               .replace(/<code>/g, '<kbd>').replace(/<\/code>/g, '<\/kbd>')
91043             };
91044           });
91045           var helpPane = uiPane('help', context).key(_t('help.key')).label(_t.html('help.title')).description(_t.html('help.title')).iconName('iD-icon-help');
91046
91047           helpPane.renderContent = function (content) {
91048             function clickHelp(d, i) {
91049               var rtl = _mainLocalizer.textDirection() === 'rtl';
91050               content.property('scrollTop', 0);
91051               helpPane.selection().select('.pane-heading h2').html(d.title);
91052               body.html(d.content);
91053               body.selectAll('a').attr('target', '_blank');
91054               menuItems.classed('selected', function (m) {
91055                 return m.title === d.title;
91056               });
91057               nav.html('');
91058
91059               if (rtl) {
91060                 nav.call(drawNext).call(drawPrevious);
91061               } else {
91062                 nav.call(drawPrevious).call(drawNext);
91063               }
91064
91065               function drawNext(selection) {
91066                 if (i < docs.length - 1) {
91067                   var nextLink = selection.append('a').attr('href', '#').attr('class', 'next').on('click', function (d3_event) {
91068                     d3_event.preventDefault();
91069                     clickHelp(docs[i + 1], i + 1);
91070                   });
91071                   nextLink.append('span').html(docs[i + 1].title).call(svgIcon(rtl ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
91072                 }
91073               }
91074
91075               function drawPrevious(selection) {
91076                 if (i > 0) {
91077                   var prevLink = selection.append('a').attr('href', '#').attr('class', 'previous').on('click', function (d3_event) {
91078                     d3_event.preventDefault();
91079                     clickHelp(docs[i - 1], i - 1);
91080                   });
91081                   prevLink.call(svgIcon(rtl ? '#iD-icon-forward' : '#iD-icon-backward', 'inline')).append('span').html(docs[i - 1].title);
91082                 }
91083               }
91084             }
91085
91086             function clickWalkthrough(d3_event) {
91087               d3_event.preventDefault();
91088               if (context.inIntro()) return;
91089               context.container().call(uiIntro(context));
91090               context.ui().togglePanes();
91091             }
91092
91093             function clickShortcuts(d3_event) {
91094               d3_event.preventDefault();
91095               context.container().call(context.ui().shortcuts, true);
91096             }
91097
91098             var toc = content.append('ul').attr('class', 'toc');
91099             var menuItems = toc.selectAll('li').data(docs).enter().append('li').append('a').attr('href', '#').html(function (d) {
91100               return d.title;
91101             }).on('click', function (d3_event, d) {
91102               d3_event.preventDefault();
91103               clickHelp(d, docs.indexOf(d));
91104             });
91105             var shortcuts = toc.append('li').attr('class', 'shortcuts').call(uiTooltip().title(_t.html('shortcuts.tooltip')).keys(['?']).placement('top')).append('a').attr('href', '#').on('click', clickShortcuts);
91106             shortcuts.append('div').html(_t.html('shortcuts.title'));
91107             var walkthrough = toc.append('li').attr('class', 'walkthrough').append('a').attr('href', '#').on('click', clickWalkthrough);
91108             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
91109             walkthrough.append('div').html(_t.html('splash.walkthrough'));
91110             var helpContent = content.append('div').attr('class', 'left-content');
91111             var body = helpContent.append('div').attr('class', 'body');
91112             var nav = helpContent.append('div').attr('class', 'nav');
91113             clickHelp(docs[0], 0);
91114           };
91115
91116           return helpPane;
91117         }
91118
91119         function uiSectionValidationIssues(id, severity, context) {
91120           var _issues = [];
91121           var section = uiSection(id, context).label(function () {
91122             if (!_issues) return '';
91123             var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length);
91124             return _t('inspector.title_count', {
91125               title: _t.html('issues.' + severity + 's.list_title'),
91126               count: issueCountText
91127             });
91128           }).disclosureContent(renderDisclosureContent).shouldDisplay(function () {
91129             return _issues && _issues.length;
91130           });
91131
91132           function getOptions() {
91133             return {
91134               what: corePreferences('validate-what') || 'edited',
91135               where: corePreferences('validate-where') || 'all'
91136             };
91137           } // get and cache the issues to display, unordered
91138
91139
91140           function reloadIssues() {
91141             _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
91142           }
91143
91144           function renderDisclosureContent(selection) {
91145             var center = context.map().center();
91146             var graph = context.graph(); // sort issues by distance away from the center of the map
91147
91148             var issues = _issues.map(function withDistance(issue) {
91149               var extent = issue.extent(graph);
91150               var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
91151               return Object.assign(issue, {
91152                 dist: dist
91153               });
91154             }).sort(function byDistance(a, b) {
91155               return a.dist - b.dist;
91156             }); // cut off at 1000
91157
91158
91159             issues = issues.slice(0, 1000); //renderIgnoredIssuesReset(_warningsSelection);
91160
91161             selection.call(drawIssuesList, issues);
91162           }
91163
91164           function drawIssuesList(selection, issues) {
91165             var list = selection.selectAll('.issues-list').data([0]);
91166             list = list.enter().append('ul').attr('class', 'layer-list issues-list ' + severity + 's-list').merge(list);
91167             var items = list.selectAll('li').data(issues, function (d) {
91168               return d.id;
91169             }); // Exit
91170
91171             items.exit().remove(); // Enter
91172
91173             var itemsEnter = items.enter().append('li').attr('class', function (d) {
91174               return 'issue severity-' + d.severity;
91175             });
91176             var labelsEnter = itemsEnter.append('button').attr('class', 'issue-label').on('click', function (d3_event, d) {
91177               context.validator().focusIssue(d);
91178             }).on('mouseover', function (d3_event, d) {
91179               utilHighlightEntities(d.entityIds, true, context);
91180             }).on('mouseout', function (d3_event, d) {
91181               utilHighlightEntities(d.entityIds, false, context);
91182             });
91183             var textEnter = labelsEnter.append('span').attr('class', 'issue-text');
91184             textEnter.append('span').attr('class', 'issue-icon').each(function (d) {
91185               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
91186               select(this).call(svgIcon(iconName));
91187             });
91188             textEnter.append('span').attr('class', 'issue-message');
91189             /*
91190             labelsEnter
91191                 .append('span')
91192                 .attr('class', 'issue-autofix')
91193                 .each(function(d) {
91194                     if (!d.autoFix) return;
91195                      d3_select(this)
91196                         .append('button')
91197                         .attr('title', t('issues.fix_one.title'))
91198                         .datum(d.autoFix)  // set button datum to the autofix
91199                         .attr('class', 'autofix action')
91200                         .on('click', function(d3_event, d) {
91201                             d3_event.preventDefault();
91202                             d3_event.stopPropagation();
91203                              var issuesEntityIDs = d.issue.entityIds;
91204                             utilHighlightEntities(issuesEntityIDs.concat(d.entityIds), false, context);
91205                              context.perform.apply(context, d.autoArgs);
91206                             context.validator().validate();
91207                         })
91208                         .call(svgIcon('#iD-icon-wrench'));
91209                 });
91210             */
91211             // Update
91212
91213             items = items.merge(itemsEnter).order();
91214             items.selectAll('.issue-message').html(function (d) {
91215               return d.message(context);
91216             });
91217             /*
91218             // autofix
91219             var canAutoFix = issues.filter(function(issue) { return issue.autoFix; });
91220              var autoFixAll = selection.selectAll('.autofix-all')
91221                 .data(canAutoFix.length ? [0] : []);
91222              // exit
91223             autoFixAll.exit()
91224                 .remove();
91225              // enter
91226             var autoFixAllEnter = autoFixAll.enter()
91227                 .insert('div', '.issues-list')
91228                 .attr('class', 'autofix-all');
91229              var linkEnter = autoFixAllEnter
91230                 .append('a')
91231                 .attr('class', 'autofix-all-link')
91232                 .attr('href', '#');
91233              linkEnter
91234                 .append('span')
91235                 .attr('class', 'autofix-all-link-text')
91236                 .html(t.html('issues.fix_all.title'));
91237              linkEnter
91238                 .append('span')
91239                 .attr('class', 'autofix-all-link-icon')
91240                 .call(svgIcon('#iD-icon-wrench'));
91241              if (severity === 'warning') {
91242                 renderIgnoredIssuesReset(selection);
91243             }
91244              // update
91245             autoFixAll = autoFixAll
91246                 .merge(autoFixAllEnter);
91247              autoFixAll.selectAll('.autofix-all-link')
91248                 .on('click', function() {
91249                     context.pauseChangeDispatch();
91250                     context.perform(actionNoop());
91251                     canAutoFix.forEach(function(issue) {
91252                         var args = issue.autoFix.autoArgs.slice();  // copy
91253                         if (typeof args[args.length - 1] !== 'function') {
91254                             args.pop();
91255                         }
91256                         args.push(t('issues.fix_all.annotation'));
91257                         context.replace.apply(context, args);
91258                     });
91259                     context.resumeChangeDispatch();
91260                     context.validator().validate();
91261                 });
91262             */
91263           }
91264
91265           context.validator().on('validated.uiSectionValidationIssues' + id, function () {
91266             window.requestIdleCallback(function () {
91267               reloadIssues();
91268               section.reRender();
91269             });
91270           });
91271           context.map().on('move.uiSectionValidationIssues' + id, debounce(function () {
91272             window.requestIdleCallback(function () {
91273               if (getOptions().where === 'visible') {
91274                 // must refetch issues if they are viewport-dependent
91275                 reloadIssues();
91276               } // always reload list to re-sort-by-distance
91277
91278
91279               section.reRender();
91280             });
91281           }, 1000));
91282           return section;
91283         }
91284
91285         function uiSectionValidationOptions(context) {
91286           var section = uiSection('issues-options', context).content(renderContent);
91287
91288           function renderContent(selection) {
91289             var container = selection.selectAll('.issues-options-container').data([0]);
91290             container = container.enter().append('div').attr('class', 'issues-options-container').merge(container);
91291             var data = [{
91292               key: 'what',
91293               values: ['edited', 'all']
91294             }, {
91295               key: 'where',
91296               values: ['visible', 'all']
91297             }];
91298             var options = container.selectAll('.issues-option').data(data, function (d) {
91299               return d.key;
91300             });
91301             var optionsEnter = options.enter().append('div').attr('class', function (d) {
91302               return 'issues-option issues-option-' + d.key;
91303             });
91304             optionsEnter.append('div').attr('class', 'issues-option-title').html(function (d) {
91305               return _t.html('issues.options.' + d.key + '.title');
91306             });
91307             var valuesEnter = optionsEnter.selectAll('label').data(function (d) {
91308               return d.values.map(function (val) {
91309                 return {
91310                   value: val,
91311                   key: d.key
91312                 };
91313               });
91314             }).enter().append('label');
91315             valuesEnter.append('input').attr('type', 'radio').attr('name', function (d) {
91316               return 'issues-option-' + d.key;
91317             }).attr('value', function (d) {
91318               return d.value;
91319             }).property('checked', function (d) {
91320               return getOptions()[d.key] === d.value;
91321             }).on('change', function (d3_event, d) {
91322               updateOptionValue(d3_event, d.key, d.value);
91323             });
91324             valuesEnter.append('span').html(function (d) {
91325               return _t.html('issues.options.' + d.key + '.' + d.value);
91326             });
91327           }
91328
91329           function getOptions() {
91330             return {
91331               what: corePreferences('validate-what') || 'edited',
91332               // 'all', 'edited'
91333               where: corePreferences('validate-where') || 'all' // 'all', 'visible'
91334
91335             };
91336           }
91337
91338           function updateOptionValue(d3_event, d, val) {
91339             if (!val && d3_event && d3_event.target) {
91340               val = d3_event.target.value;
91341             }
91342
91343             corePreferences('validate-' + d, val);
91344             context.validator().validate();
91345           }
91346
91347           return section;
91348         }
91349
91350         function uiSectionValidationRules(context) {
91351           var MINSQUARE = 0;
91352           var MAXSQUARE = 20;
91353           var DEFAULTSQUARE = 5; // see also unsquare_way.js
91354
91355           var section = uiSection('issues-rules', context).disclosureContent(renderDisclosureContent).label(_t.html('issues.rules.title'));
91356
91357           var _ruleKeys = context.validator().getRuleKeys().filter(function (key) {
91358             return key !== 'maprules';
91359           }).sort(function (key1, key2) {
91360             // alphabetize by localized title
91361             return _t('issues.' + key1 + '.title') < _t('issues.' + key2 + '.title') ? -1 : 1;
91362           });
91363
91364           function renderDisclosureContent(selection) {
91365             var container = selection.selectAll('.issues-rulelist-container').data([0]);
91366             var containerEnter = container.enter().append('div').attr('class', 'issues-rulelist-container');
91367             containerEnter.append('ul').attr('class', 'layer-list issue-rules-list');
91368             var ruleLinks = containerEnter.append('div').attr('class', 'issue-rules-links section-footer');
91369             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
91370               d3_event.preventDefault();
91371               context.validator().disableRules(_ruleKeys);
91372             });
91373             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
91374               d3_event.preventDefault();
91375               context.validator().disableRules([]);
91376             }); // Update
91377
91378             container = container.merge(containerEnter);
91379             container.selectAll('.issue-rules-list').call(drawListItems, _ruleKeys, 'checkbox', 'rule', toggleRule, isRuleEnabled);
91380           }
91381
91382           function drawListItems(selection, data, type, name, change, active) {
91383             var items = selection.selectAll('li').data(data); // Exit
91384
91385             items.exit().remove(); // Enter
91386
91387             var enter = items.enter().append('li');
91388
91389             if (name === 'rule') {
91390               enter.call(uiTooltip().title(function (d) {
91391                 return _t.html('issues.' + d + '.tip');
91392               }).placement('top'));
91393             }
91394
91395             var label = enter.append('label');
91396             label.append('input').attr('type', type).attr('name', name).on('change', change);
91397             label.append('span').html(function (d) {
91398               var params = {};
91399
91400               if (d === 'unsquare_way') {
91401                 params.val = '<span class="square-degrees"></span>';
91402               }
91403
91404               return _t.html('issues.' + d + '.title', params);
91405             }); // Update
91406
91407             items = items.merge(enter);
91408             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false); // user-configurable square threshold
91409
91410             var degStr = corePreferences('validate-square-degrees');
91411
91412             if (degStr === null) {
91413               degStr = DEFAULTSQUARE.toString();
91414             }
91415
91416             var span = items.selectAll('.square-degrees');
91417             var input = span.selectAll('.square-degrees-input').data([0]); // enter / update
91418
91419             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) {
91420               d3_event.preventDefault();
91421               d3_event.stopPropagation();
91422               this.select();
91423             }).on('keyup', function (d3_event) {
91424               if (d3_event.keyCode === 13) {
91425                 // ↩ Return
91426                 this.blur();
91427                 this.select();
91428               }
91429             }).on('blur', changeSquare).merge(input).property('value', degStr);
91430           }
91431
91432           function changeSquare() {
91433             var input = select(this);
91434             var degStr = utilGetSetValue(input).trim();
91435             var degNum = parseFloat(degStr, 10);
91436
91437             if (!isFinite(degNum)) {
91438               degNum = DEFAULTSQUARE;
91439             } else if (degNum > MAXSQUARE) {
91440               degNum = MAXSQUARE;
91441             } else if (degNum < MINSQUARE) {
91442               degNum = MINSQUARE;
91443             }
91444
91445             degNum = Math.round(degNum * 10) / 10; // round to 1 decimal
91446
91447             degStr = degNum.toString();
91448             input.property('value', degStr);
91449             corePreferences('validate-square-degrees', degStr);
91450             context.validator().revalidateUnsquare();
91451           }
91452
91453           function isRuleEnabled(d) {
91454             return context.validator().isRuleEnabled(d);
91455           }
91456
91457           function toggleRule(d3_event, d) {
91458             context.validator().toggleRule(d);
91459           }
91460
91461           context.validator().on('validated.uiSectionValidationRules', function () {
91462             window.requestIdleCallback(section.reRender);
91463           });
91464           return section;
91465         }
91466
91467         function uiSectionValidationStatus(context) {
91468           var section = uiSection('issues-status', context).content(renderContent).shouldDisplay(function () {
91469             var issues = context.validator().getIssues(getOptions());
91470             return issues.length === 0;
91471           });
91472
91473           function getOptions() {
91474             return {
91475               what: corePreferences('validate-what') || 'edited',
91476               where: corePreferences('validate-where') || 'all'
91477             };
91478           }
91479
91480           function renderContent(selection) {
91481             var box = selection.selectAll('.box').data([0]);
91482             var boxEnter = box.enter().append('div').attr('class', 'box');
91483             boxEnter.append('div').call(svgIcon('#iD-icon-apply', 'pre-text'));
91484             var noIssuesMessage = boxEnter.append('span');
91485             noIssuesMessage.append('strong').attr('class', 'message');
91486             noIssuesMessage.append('br');
91487             noIssuesMessage.append('span').attr('class', 'details');
91488             renderIgnoredIssuesReset(selection);
91489             setNoIssuesText(selection);
91490           }
91491
91492           function renderIgnoredIssuesReset(selection) {
91493             var ignoredIssues = context.validator().getIssues({
91494               what: 'all',
91495               where: 'all',
91496               includeDisabledRules: true,
91497               includeIgnored: 'only'
91498             });
91499             var resetIgnored = selection.selectAll('.reset-ignored').data(ignoredIssues.length ? [0] : []); // exit
91500
91501             resetIgnored.exit().remove(); // enter
91502
91503             var resetIgnoredEnter = resetIgnored.enter().append('div').attr('class', 'reset-ignored section-footer');
91504             resetIgnoredEnter.append('a').attr('href', '#'); // update
91505
91506             resetIgnored = resetIgnored.merge(resetIgnoredEnter);
91507             resetIgnored.select('a').html(_t('inspector.title_count', {
91508               title: _t.html('issues.reset_ignored'),
91509               count: ignoredIssues.length
91510             }));
91511             resetIgnored.on('click', function (d3_event) {
91512               d3_event.preventDefault();
91513               context.validator().resetIgnoredIssues();
91514             });
91515           }
91516
91517           function setNoIssuesText(selection) {
91518             var opts = getOptions();
91519
91520             function checkForHiddenIssues(cases) {
91521               for (var type in cases) {
91522                 var hiddenOpts = cases[type];
91523                 var hiddenIssues = context.validator().getIssues(hiddenOpts);
91524
91525                 if (hiddenIssues.length) {
91526                   selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.' + type, {
91527                     count: hiddenIssues.length.toString()
91528                   }));
91529                   return;
91530                 }
91531               }
91532
91533               selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.none'));
91534             }
91535
91536             var messageType;
91537
91538             if (opts.what === 'edited' && opts.where === 'visible') {
91539               messageType = 'edits_in_view';
91540               checkForHiddenIssues({
91541                 elsewhere: {
91542                   what: 'edited',
91543                   where: 'all'
91544                 },
91545                 everything_else: {
91546                   what: 'all',
91547                   where: 'visible'
91548                 },
91549                 disabled_rules: {
91550                   what: 'edited',
91551                   where: 'visible',
91552                   includeDisabledRules: 'only'
91553                 },
91554                 everything_else_elsewhere: {
91555                   what: 'all',
91556                   where: 'all'
91557                 },
91558                 disabled_rules_elsewhere: {
91559                   what: 'edited',
91560                   where: 'all',
91561                   includeDisabledRules: 'only'
91562                 },
91563                 ignored_issues: {
91564                   what: 'edited',
91565                   where: 'visible',
91566                   includeIgnored: 'only'
91567                 },
91568                 ignored_issues_elsewhere: {
91569                   what: 'edited',
91570                   where: 'all',
91571                   includeIgnored: 'only'
91572                 }
91573               });
91574             } else if (opts.what === 'edited' && opts.where === 'all') {
91575               messageType = 'edits';
91576               checkForHiddenIssues({
91577                 everything_else: {
91578                   what: 'all',
91579                   where: 'all'
91580                 },
91581                 disabled_rules: {
91582                   what: 'edited',
91583                   where: 'all',
91584                   includeDisabledRules: 'only'
91585                 },
91586                 ignored_issues: {
91587                   what: 'edited',
91588                   where: 'all',
91589                   includeIgnored: 'only'
91590                 }
91591               });
91592             } else if (opts.what === 'all' && opts.where === 'visible') {
91593               messageType = 'everything_in_view';
91594               checkForHiddenIssues({
91595                 elsewhere: {
91596                   what: 'all',
91597                   where: 'all'
91598                 },
91599                 disabled_rules: {
91600                   what: 'all',
91601                   where: 'visible',
91602                   includeDisabledRules: 'only'
91603                 },
91604                 disabled_rules_elsewhere: {
91605                   what: 'all',
91606                   where: 'all',
91607                   includeDisabledRules: 'only'
91608                 },
91609                 ignored_issues: {
91610                   what: 'all',
91611                   where: 'visible',
91612                   includeIgnored: 'only'
91613                 },
91614                 ignored_issues_elsewhere: {
91615                   what: 'all',
91616                   where: 'all',
91617                   includeIgnored: 'only'
91618                 }
91619               });
91620             } else if (opts.what === 'all' && opts.where === 'all') {
91621               messageType = 'everything';
91622               checkForHiddenIssues({
91623                 disabled_rules: {
91624                   what: 'all',
91625                   where: 'all',
91626                   includeDisabledRules: 'only'
91627                 },
91628                 ignored_issues: {
91629                   what: 'all',
91630                   where: 'all',
91631                   includeIgnored: 'only'
91632                 }
91633               });
91634             }
91635
91636             if (opts.what === 'edited' && context.history().difference().summary().length === 0) {
91637               messageType = 'no_edits';
91638             }
91639
91640             selection.select('.box .message').html(_t.html('issues.no_issues.message.' + messageType));
91641           }
91642
91643           context.validator().on('validated.uiSectionValidationStatus', function () {
91644             window.requestIdleCallback(section.reRender);
91645           });
91646           context.map().on('move.uiSectionValidationStatus', debounce(function () {
91647             window.requestIdleCallback(section.reRender);
91648           }, 1000));
91649           return section;
91650         }
91651
91652         function uiPaneIssues(context) {
91653           var issuesPane = uiPane('issues', context).key(_t('issues.key')).label(_t.html('issues.title')).description(_t.html('issues.title')).iconName('iD-icon-alert').sections([uiSectionValidationOptions(context), uiSectionValidationStatus(context), uiSectionValidationIssues('issues-errors', 'error', context), uiSectionValidationIssues('issues-warnings', 'warning', context), uiSectionValidationRules(context)]);
91654           return issuesPane;
91655         }
91656
91657         function uiSettingsCustomData(context) {
91658           var dispatch = dispatch$8('change');
91659
91660           function render(selection) {
91661             var dataLayer = context.layers().layer('data'); // keep separate copies of original and current settings
91662
91663             var _origSettings = {
91664               fileList: dataLayer && dataLayer.fileList() || null,
91665               url: corePreferences('settings-custom-data-url')
91666             };
91667             var _currSettings = {
91668               fileList: dataLayer && dataLayer.fileList() || null,
91669               url: corePreferences('settings-custom-data-url')
91670             }; // var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
91671
91672             var modal = uiConfirm(selection).okButton();
91673             modal.classed('settings-modal settings-custom-data', true);
91674             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_data.header'));
91675             var textSection = modal.select('.modal-section.message-text');
91676             textSection.append('pre').attr('class', 'instructions-file').html(_t.html('settings.custom_data.file.instructions'));
91677             textSection.append('input').attr('class', 'field-file').attr('type', 'file').property('files', _currSettings.fileList) // works for all except IE11
91678             .on('change', function (d3_event) {
91679               var files = d3_event.target.files;
91680
91681               if (files && files.length) {
91682                 _currSettings.url = '';
91683                 textSection.select('.field-url').property('value', '');
91684                 _currSettings.fileList = files;
91685               } else {
91686                 _currSettings.fileList = null;
91687               }
91688             });
91689             textSection.append('h4').html(_t.html('settings.custom_data.or'));
91690             textSection.append('pre').attr('class', 'instructions-url').html(_t.html('settings.custom_data.url.instructions'));
91691             textSection.append('textarea').attr('class', 'field-url').attr('placeholder', _t('settings.custom_data.url.placeholder')).call(utilNoAuto).property('value', _currSettings.url); // insert a cancel button
91692
91693             var buttonSection = modal.select('.modal-section.buttons');
91694             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
91695             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
91696             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
91697
91698             function isSaveDisabled() {
91699               return null;
91700             } // restore the original url
91701
91702
91703             function clickCancel() {
91704               textSection.select('.field-url').property('value', _origSettings.url);
91705               corePreferences('settings-custom-data-url', _origSettings.url);
91706               this.blur();
91707               modal.close();
91708             } // accept the current url
91709
91710
91711             function clickSave() {
91712               _currSettings.url = textSection.select('.field-url').property('value').trim(); // one or the other but not both
91713
91714               if (_currSettings.url) {
91715                 _currSettings.fileList = null;
91716               }
91717
91718               if (_currSettings.fileList) {
91719                 _currSettings.url = '';
91720               }
91721
91722               corePreferences('settings-custom-data-url', _currSettings.url);
91723               this.blur();
91724               modal.close();
91725               dispatch.call('change', this, _currSettings);
91726             }
91727           }
91728
91729           return utilRebind(render, dispatch, 'on');
91730         }
91731
91732         function uiSectionDataLayers(context) {
91733           var settingsCustomData = uiSettingsCustomData(context).on('change', customChanged);
91734           var layers = context.layers();
91735           var section = uiSection('data-layers', context).label(_t.html('map_data.data_layers')).disclosureContent(renderDisclosureContent);
91736
91737           function renderDisclosureContent(selection) {
91738             var container = selection.selectAll('.data-layer-container').data([0]);
91739             container.enter().append('div').attr('class', 'data-layer-container').merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems) // Beta - Detroit mapping challenge
91740             .call(drawPanelItems);
91741           }
91742
91743           function showsLayer(which) {
91744             var layer = layers.layer(which);
91745
91746             if (layer) {
91747               return layer.enabled();
91748             }
91749
91750             return false;
91751           }
91752
91753           function setLayer(which, enabled) {
91754             // Don't allow layer changes while drawing - #6584
91755             var mode = context.mode();
91756             if (mode && /^draw/.test(mode.id)) return;
91757             var layer = layers.layer(which);
91758
91759             if (layer) {
91760               layer.enabled(enabled);
91761
91762               if (!enabled && (which === 'osm' || which === 'notes')) {
91763                 context.enter(modeBrowse(context));
91764               }
91765             }
91766           }
91767
91768           function toggleLayer(which) {
91769             setLayer(which, !showsLayer(which));
91770           }
91771
91772           function drawOsmItems(selection) {
91773             var osmKeys = ['osm', 'notes'];
91774             var osmLayers = layers.all().filter(function (obj) {
91775               return osmKeys.indexOf(obj.id) !== -1;
91776             });
91777             var ul = selection.selectAll('.layer-list-osm').data([0]);
91778             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-osm').merge(ul);
91779             var li = ul.selectAll('.list-item').data(osmLayers);
91780             li.exit().remove();
91781             var liEnter = li.enter().append('li').attr('class', function (d) {
91782               return 'list-item list-item-' + d.id;
91783             });
91784             var labelEnter = liEnter.append('label').each(function (d) {
91785               if (d.id === 'osm') {
91786                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).keys([uiCmd('⌥' + _t('area_fill.wireframe.key'))]).placement('bottom'));
91787               } else {
91788                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
91789               }
91790             });
91791             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
91792               toggleLayer(d.id);
91793             });
91794             labelEnter.append('span').html(function (d) {
91795               return _t.html('map_data.layers.' + d.id + '.title');
91796             }); // Update
91797
91798             li.merge(liEnter).classed('active', function (d) {
91799               return d.layer.enabled();
91800             }).selectAll('input').property('checked', function (d) {
91801               return d.layer.enabled();
91802             });
91803           }
91804
91805           function drawQAItems(selection) {
91806             var qaKeys = ['keepRight', 'improveOSM', 'osmose'];
91807             var qaLayers = layers.all().filter(function (obj) {
91808               return qaKeys.indexOf(obj.id) !== -1;
91809             });
91810             var ul = selection.selectAll('.layer-list-qa').data([0]);
91811             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-qa').merge(ul);
91812             var li = ul.selectAll('.list-item').data(qaLayers);
91813             li.exit().remove();
91814             var liEnter = li.enter().append('li').attr('class', function (d) {
91815               return 'list-item list-item-' + d.id;
91816             });
91817             var labelEnter = liEnter.append('label').each(function (d) {
91818               select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
91819             });
91820             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
91821               toggleLayer(d.id);
91822             });
91823             labelEnter.append('span').html(function (d) {
91824               return _t.html('map_data.layers.' + d.id + '.title');
91825             }); // Update
91826
91827             li.merge(liEnter).classed('active', function (d) {
91828               return d.layer.enabled();
91829             }).selectAll('input').property('checked', function (d) {
91830               return d.layer.enabled();
91831             });
91832           } // Beta feature - sample vector layers to support Detroit Mapping Challenge
91833           // https://github.com/osmus/detroit-mapping-challenge
91834
91835
91836           function drawVectorItems(selection) {
91837             var dataLayer = layers.layer('data');
91838             var vtData = [{
91839               name: 'Detroit Neighborhoods/Parks',
91840               src: 'neighborhoods-parks',
91841               tooltip: 'Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.',
91842               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'
91843             }, {
91844               name: 'Detroit Composite POIs',
91845               src: 'composite-poi',
91846               tooltip: 'Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.',
91847               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'
91848             }, {
91849               name: 'Detroit All-The-Places POIs',
91850               src: 'alltheplaces-poi',
91851               tooltip: 'Public domain business location data created by web scrapers.',
91852               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'
91853             }]; // Only show this if the map is around Detroit..
91854
91855             var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
91856             var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
91857             var container = selection.selectAll('.vectortile-container').data(showVectorItems ? [0] : []);
91858             container.exit().remove();
91859             var containerEnter = container.enter().append('div').attr('class', 'vectortile-container');
91860             containerEnter.append('h4').attr('class', 'vectortile-header').html('Detroit Vector Tiles (Beta)');
91861             containerEnter.append('ul').attr('class', 'layer-list layer-list-vectortile');
91862             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').html('About these layers');
91863             container = container.merge(containerEnter);
91864             var ul = container.selectAll('.layer-list-vectortile');
91865             var li = ul.selectAll('.list-item').data(vtData);
91866             li.exit().remove();
91867             var liEnter = li.enter().append('li').attr('class', function (d) {
91868               return 'list-item list-item-' + d.src;
91869             });
91870             var labelEnter = liEnter.append('label').each(function (d) {
91871               select(this).call(uiTooltip().title(d.tooltip).placement('top'));
91872             });
91873             labelEnter.append('input').attr('type', 'radio').attr('name', 'vectortile').on('change', selectVTLayer);
91874             labelEnter.append('span').html(function (d) {
91875               return d.name;
91876             }); // Update
91877
91878             li.merge(liEnter).classed('active', isVTLayerSelected).selectAll('input').property('checked', isVTLayerSelected);
91879
91880             function isVTLayerSelected(d) {
91881               return dataLayer && dataLayer.template() === d.template;
91882             }
91883
91884             function selectVTLayer(d3_event, d) {
91885               corePreferences('settings-custom-data-url', d.template);
91886
91887               if (dataLayer) {
91888                 dataLayer.template(d.template, d.src);
91889                 dataLayer.enabled(true);
91890               }
91891             }
91892           }
91893
91894           function drawCustomDataItems(selection) {
91895             var dataLayer = layers.layer('data');
91896             var hasData = dataLayer && dataLayer.hasData();
91897             var showsData = hasData && dataLayer.enabled();
91898             var ul = selection.selectAll('.layer-list-data').data(dataLayer ? [0] : []); // Exit
91899
91900             ul.exit().remove(); // Enter
91901
91902             var ulEnter = ul.enter().append('ul').attr('class', 'layer-list layer-list-data');
91903             var liEnter = ulEnter.append('li').attr('class', 'list-item-data');
91904             var labelEnter = liEnter.append('label').call(uiTooltip().title(_t.html('map_data.layers.custom.tooltip')).placement('top'));
91905             labelEnter.append('input').attr('type', 'checkbox').on('change', function () {
91906               toggleLayer('data');
91907             });
91908             labelEnter.append('span').html(_t.html('map_data.layers.custom.title'));
91909             liEnter.append('button').attr('class', 'open-data-options').call(uiTooltip().title(_t.html('settings.custom_data.tooltip')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).on('click', function (d3_event) {
91910               d3_event.preventDefault();
91911               editCustom();
91912             }).call(svgIcon('#iD-icon-more'));
91913             liEnter.append('button').attr('class', 'zoom-to-data').call(uiTooltip().title(_t.html('map_data.layers.custom.zoom')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).on('click', function (d3_event) {
91914               if (select(this).classed('disabled')) return;
91915               d3_event.preventDefault();
91916               d3_event.stopPropagation();
91917               dataLayer.fitZoom();
91918             }).call(svgIcon('#iD-icon-framed-dot', 'monochrome')); // Update
91919
91920             ul = ul.merge(ulEnter);
91921             ul.selectAll('.list-item-data').classed('active', showsData).selectAll('label').classed('deemphasize', !hasData).selectAll('input').property('disabled', !hasData).property('checked', showsData);
91922             ul.selectAll('button.zoom-to-data').classed('disabled', !hasData);
91923           }
91924
91925           function editCustom() {
91926             context.container().call(settingsCustomData);
91927           }
91928
91929           function customChanged(d) {
91930             var dataLayer = layers.layer('data');
91931
91932             if (d && d.url) {
91933               dataLayer.url(d.url);
91934             } else if (d && d.fileList) {
91935               dataLayer.fileList(d.fileList);
91936             }
91937           }
91938
91939           function drawPanelItems(selection) {
91940             var panelsListEnter = selection.selectAll('.md-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list md-extras-list');
91941             var historyPanelLabelEnter = panelsListEnter.append('li').attr('class', 'history-panel-toggle-item').append('label').call(uiTooltip().title(_t.html('map_data.history_panel.tooltip')).keys([uiCmd('⌘⇧' + _t('info_panels.history.key'))]).placement('top'));
91942             historyPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
91943               d3_event.preventDefault();
91944               context.ui().info.toggle('history');
91945             });
91946             historyPanelLabelEnter.append('span').html(_t.html('map_data.history_panel.title'));
91947             var measurementPanelLabelEnter = panelsListEnter.append('li').attr('class', 'measurement-panel-toggle-item').append('label').call(uiTooltip().title(_t.html('map_data.measurement_panel.tooltip')).keys([uiCmd('⌘⇧' + _t('info_panels.measurement.key'))]).placement('top'));
91948             measurementPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
91949               d3_event.preventDefault();
91950               context.ui().info.toggle('measurement');
91951             });
91952             measurementPanelLabelEnter.append('span').html(_t.html('map_data.measurement_panel.title'));
91953           }
91954
91955           context.layers().on('change.uiSectionDataLayers', section.reRender);
91956           context.map().on('move.uiSectionDataLayers', debounce(function () {
91957             // Detroit layers may have moved in or out of view
91958             window.requestIdleCallback(section.reRender);
91959           }, 1000));
91960           return section;
91961         }
91962
91963         function uiSectionMapFeatures(context) {
91964           var _features = context.features().keys();
91965
91966           var section = uiSection('map-features', context).label(_t.html('map_data.map_features')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
91967
91968           function renderDisclosureContent(selection) {
91969             var container = selection.selectAll('.layer-feature-list-container').data([0]);
91970             var containerEnter = container.enter().append('div').attr('class', 'layer-feature-list-container');
91971             containerEnter.append('ul').attr('class', 'layer-list layer-feature-list');
91972             var footer = containerEnter.append('div').attr('class', 'feature-list-links section-footer');
91973             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
91974               d3_event.preventDefault();
91975               context.features().disableAll();
91976             });
91977             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
91978               d3_event.preventDefault();
91979               context.features().enableAll();
91980             }); // Update
91981
91982             container = container.merge(containerEnter);
91983             container.selectAll('.layer-feature-list').call(drawListItems, _features, 'checkbox', 'feature', clickFeature, showsFeature);
91984           }
91985
91986           function drawListItems(selection, data, type, name, change, active) {
91987             var items = selection.selectAll('li').data(data); // Exit
91988
91989             items.exit().remove(); // Enter
91990
91991             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
91992               var tip = _t.html(name + '.' + d + '.tooltip');
91993
91994               if (autoHiddenFeature(d)) {
91995                 var msg = showsLayer('osm') ? _t.html('map_data.autohidden') : _t.html('map_data.osmhidden');
91996                 tip += '<div>' + msg + '</div>';
91997               }
91998
91999               return tip;
92000             }).placement('top'));
92001             var label = enter.append('label');
92002             label.append('input').attr('type', type).attr('name', name).on('change', change);
92003             label.append('span').html(function (d) {
92004               return _t.html(name + '.' + d + '.description');
92005             }); // Update
92006
92007             items = items.merge(enter);
92008             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', autoHiddenFeature);
92009           }
92010
92011           function autoHiddenFeature(d) {
92012             return context.features().autoHidden(d);
92013           }
92014
92015           function showsFeature(d) {
92016             return context.features().enabled(d);
92017           }
92018
92019           function clickFeature(d3_event, d) {
92020             context.features().toggle(d);
92021           }
92022
92023           function showsLayer(id) {
92024             var layer = context.layers().layer(id);
92025             return layer && layer.enabled();
92026           } // add listeners
92027
92028
92029           context.features().on('change.map_features', section.reRender);
92030           return section;
92031         }
92032
92033         function uiSectionMapStyleOptions(context) {
92034           var section = uiSection('fill-area', context).label(_t.html('map_data.style_options')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
92035
92036           function renderDisclosureContent(selection) {
92037             var container = selection.selectAll('.layer-fill-list').data([0]);
92038             container.enter().append('ul').attr('class', 'layer-list layer-fill-list').merge(container).call(drawListItems, context.map().areaFillOptions, 'radio', 'area_fill', setFill, isActiveFill);
92039             var container2 = selection.selectAll('.layer-visual-diff-list').data([0]);
92040             container2.enter().append('ul').attr('class', 'layer-list layer-visual-diff-list').merge(container2).call(drawListItems, ['highlight_edits'], 'checkbox', 'visual_diff', toggleHighlightEdited, function () {
92041               return context.surface().classed('highlight-edited');
92042             });
92043           }
92044
92045           function drawListItems(selection, data, type, name, change, active) {
92046             var items = selection.selectAll('li').data(data); // Exit
92047
92048             items.exit().remove(); // Enter
92049
92050             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
92051               return _t.html(name + '.' + d + '.tooltip');
92052             }).keys(function (d) {
92053               var key = d === 'wireframe' ? _t('area_fill.wireframe.key') : null;
92054               if (d === 'highlight_edits') key = _t('map_data.highlight_edits.key');
92055               return key ? [key] : null;
92056             }).placement('top'));
92057             var label = enter.append('label');
92058             label.append('input').attr('type', type).attr('name', name).on('change', change);
92059             label.append('span').html(function (d) {
92060               return _t.html(name + '.' + d + '.description');
92061             }); // Update
92062
92063             items = items.merge(enter);
92064             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false);
92065           }
92066
92067           function isActiveFill(d) {
92068             return context.map().activeAreaFill() === d;
92069           }
92070
92071           function toggleHighlightEdited(d3_event) {
92072             d3_event.preventDefault();
92073             context.map().toggleHighlightEdited();
92074           }
92075
92076           function setFill(d3_event, d) {
92077             context.map().activeAreaFill(d);
92078           }
92079
92080           context.map().on('changeHighlighting.ui_style, changeAreaFill.ui_style', section.reRender);
92081           return section;
92082         }
92083
92084         function uiSectionPhotoOverlays(context) {
92085           var layers = context.layers();
92086           var section = uiSection('photo-overlays', context).label(_t.html('photo_overlays.title')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
92087
92088           function renderDisclosureContent(selection) {
92089             var container = selection.selectAll('.photo-overlay-container').data([0]);
92090             container.enter().append('div').attr('class', 'photo-overlay-container').merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter);
92091           }
92092
92093           function drawPhotoItems(selection) {
92094             var photoKeys = context.photos().overlayLayerIDs();
92095             var photoLayers = layers.all().filter(function (obj) {
92096               return photoKeys.indexOf(obj.id) !== -1;
92097             });
92098             var data = photoLayers.filter(function (obj) {
92099               return obj.layer.supported();
92100             });
92101
92102             function layerSupported(d) {
92103               return d.layer && d.layer.supported();
92104             }
92105
92106             function layerEnabled(d) {
92107               return layerSupported(d) && d.layer.enabled();
92108             }
92109
92110             var ul = selection.selectAll('.layer-list-photos').data([0]);
92111             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photos').merge(ul);
92112             var li = ul.selectAll('.list-item-photos').data(data);
92113             li.exit().remove();
92114             var liEnter = li.enter().append('li').attr('class', function (d) {
92115               var classes = 'list-item-photos list-item-' + d.id;
92116
92117               if (d.id === 'mapillary-signs' || d.id === 'mapillary-map-features') {
92118                 classes += ' indented';
92119               }
92120
92121               return classes;
92122             });
92123             var labelEnter = liEnter.append('label').each(function (d) {
92124               var titleID;
92125               if (d.id === 'mapillary-signs') titleID = 'mapillary.signs.tooltip';else if (d.id === 'mapillary') titleID = 'mapillary_images.tooltip';else if (d.id === 'openstreetcam') titleID = 'openstreetcam_images.tooltip';else titleID = d.id.replace(/-/g, '_') + '.tooltip';
92126               select(this).call(uiTooltip().title(_t.html(titleID)).placement('top'));
92127             });
92128             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
92129               toggleLayer(d.id);
92130             });
92131             labelEnter.append('span').html(function (d) {
92132               var id = d.id;
92133               if (id === 'mapillary-signs') id = 'photo_overlays.traffic_signs';
92134               return _t.html(id.replace(/-/g, '_') + '.title');
92135             }); // Update
92136
92137             li.merge(liEnter).classed('active', layerEnabled).selectAll('input').property('checked', layerEnabled);
92138           }
92139
92140           function drawPhotoTypeItems(selection) {
92141             var data = context.photos().allPhotoTypes();
92142
92143             function typeEnabled(d) {
92144               return context.photos().showsPhotoType(d);
92145             }
92146
92147             var ul = selection.selectAll('.layer-list-photo-types').data([0]);
92148             ul.exit().remove();
92149             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photo-types').merge(ul);
92150             var li = ul.selectAll('.list-item-photo-types').data(context.photos().shouldFilterByPhotoType() ? data : []);
92151             li.exit().remove();
92152             var liEnter = li.enter().append('li').attr('class', function (d) {
92153               return 'list-item-photo-types list-item-' + d;
92154             });
92155             var labelEnter = liEnter.append('label').each(function (d) {
92156               select(this).call(uiTooltip().title(_t.html('photo_overlays.photo_type.' + d + '.tooltip')).placement('top'));
92157             });
92158             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
92159               context.photos().togglePhotoType(d);
92160             });
92161             labelEnter.append('span').html(function (d) {
92162               return _t.html('photo_overlays.photo_type.' + d + '.title');
92163             }); // Update
92164
92165             li.merge(liEnter).classed('active', typeEnabled).selectAll('input').property('checked', typeEnabled);
92166           }
92167
92168           function drawDateFilter(selection) {
92169             var data = context.photos().dateFilters();
92170
92171             function filterEnabled(d) {
92172               return context.photos().dateFilterValue(d);
92173             }
92174
92175             var ul = selection.selectAll('.layer-list-date-filter').data([0]);
92176             ul.exit().remove();
92177             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-date-filter').merge(ul);
92178             var li = ul.selectAll('.list-item-date-filter').data(context.photos().shouldFilterByDate() ? data : []);
92179             li.exit().remove();
92180             var liEnter = li.enter().append('li').attr('class', 'list-item-date-filter');
92181             var labelEnter = liEnter.append('label').each(function (d) {
92182               select(this).call(uiTooltip().title(_t.html('photo_overlays.date_filter.' + d + '.tooltip')).placement('top'));
92183             });
92184             labelEnter.append('span').html(function (d) {
92185               return _t.html('photo_overlays.date_filter.' + d + '.title');
92186             });
92187             labelEnter.append('input').attr('type', 'date').attr('class', 'list-item-input').attr('placeholder', _t('units.year_month_day')).call(utilNoAuto).each(function (d) {
92188               utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
92189             }).on('change', function (d3_event, d) {
92190               var value = utilGetSetValue(select(this)).trim();
92191               context.photos().setDateFilter(d, value, true); // reload the displayed dates
92192
92193               li.selectAll('input').each(function (d) {
92194                 utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
92195               });
92196             });
92197             li = li.merge(liEnter).classed('active', filterEnabled);
92198           }
92199
92200           function drawUsernameFilter(selection) {
92201             function filterEnabled() {
92202               return context.photos().usernames();
92203             }
92204
92205             var ul = selection.selectAll('.layer-list-username-filter').data([0]);
92206             ul.exit().remove();
92207             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-username-filter').merge(ul);
92208             var li = ul.selectAll('.list-item-username-filter').data(context.photos().shouldFilterByUsername() ? ['username-filter'] : []);
92209             li.exit().remove();
92210             var liEnter = li.enter().append('li').attr('class', 'list-item-username-filter');
92211             var labelEnter = liEnter.append('label').each(function () {
92212               select(this).call(uiTooltip().title(_t.html('photo_overlays.username_filter.tooltip')).placement('top'));
92213             });
92214             labelEnter.append('span').html(_t.html('photo_overlays.username_filter.title'));
92215             labelEnter.append('input').attr('type', 'text').attr('class', 'list-item-input').call(utilNoAuto).property('value', usernameValue).on('change', function () {
92216               var value = select(this).property('value');
92217               context.photos().setUsernameFilter(value, true);
92218               select(this).property('value', usernameValue);
92219             });
92220             li.merge(liEnter).classed('active', filterEnabled);
92221
92222             function usernameValue() {
92223               var usernames = context.photos().usernames();
92224               if (usernames) return usernames.join('; ');
92225               return usernames;
92226             }
92227           }
92228
92229           function toggleLayer(which) {
92230             setLayer(which, !showsLayer(which));
92231           }
92232
92233           function showsLayer(which) {
92234             var layer = layers.layer(which);
92235
92236             if (layer) {
92237               return layer.enabled();
92238             }
92239
92240             return false;
92241           }
92242
92243           function setLayer(which, enabled) {
92244             var layer = layers.layer(which);
92245
92246             if (layer) {
92247               layer.enabled(enabled);
92248             }
92249           }
92250
92251           context.layers().on('change.uiSectionPhotoOverlays', section.reRender);
92252           context.photos().on('change.uiSectionPhotoOverlays', section.reRender);
92253           return section;
92254         }
92255
92256         function uiPaneMapData(context) {
92257           var mapDataPane = uiPane('map-data', context).key(_t('map_data.key')).label(_t.html('map_data.title')).description(_t.html('map_data.description')).iconName('iD-icon-data').sections([uiSectionDataLayers(context), uiSectionPhotoOverlays(context), uiSectionMapStyleOptions(context), uiSectionMapFeatures(context)]);
92258           return mapDataPane;
92259         }
92260
92261         function uiSectionPrivacy(context) {
92262           var section = uiSection('preferences-third-party', context).label(_t.html('preferences.privacy.title')).disclosureContent(renderDisclosureContent);
92263
92264           var _showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
92265
92266           function renderDisclosureContent(selection) {
92267             // enter
92268             var privacyOptionsListEnter = selection.selectAll('.privacy-options-list').data([0]).enter().append('ul').attr('class', 'layer-list privacy-options-list');
92269             var thirdPartyIconsEnter = privacyOptionsListEnter.append('li').attr('class', 'privacy-third-party-icons-item').append('label').call(uiTooltip().title(_t.html('preferences.privacy.third_party_icons.tooltip')).placement('bottom'));
92270             thirdPartyIconsEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
92271               d3_event.preventDefault();
92272               _showThirdPartyIcons = _showThirdPartyIcons === 'true' ? 'false' : 'true';
92273               corePreferences('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
92274               update();
92275             });
92276             thirdPartyIconsEnter.append('span').html(_t.html('preferences.privacy.third_party_icons.description')); // Privacy Policy link
92277
92278             selection.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').html(_t.html('preferences.privacy.privacy_link'));
92279             update();
92280
92281             function update() {
92282               selection.selectAll('.privacy-third-party-icons-item').classed('active', _showThirdPartyIcons === 'true').select('input').property('checked', _showThirdPartyIcons === 'true');
92283             }
92284           }
92285
92286           return section;
92287         }
92288
92289         function uiPanePreferences(context) {
92290           var preferencesPane = uiPane('preferences', context).key(_t('preferences.key')).label(_t.html('preferences.title')).description(_t.html('preferences.description')).iconName('fas-user-cog').sections([uiSectionPrivacy(context)]);
92291           return preferencesPane;
92292         }
92293
92294         function uiInit(context) {
92295           var _initCounter = 0;
92296           var _needWidth = {};
92297
92298           var _lastPointerType;
92299
92300           function render(container) {
92301             container.on('click.ui', function (d3_event) {
92302               // we're only concerned with the primary mouse button
92303               if (d3_event.button !== 0) return;
92304               if (!d3_event.composedPath) return; // some targets have default click events we don't want to override
92305
92306               var isOkayTarget = d3_event.composedPath().some(function (node) {
92307                 // we only care about element nodes
92308                 return node.nodeType === 1 && ( // clicking <input> focuses it and/or changes a value
92309                 node.nodeName === 'INPUT' || // clicking <label> affects its <input> by default
92310                 node.nodeName === 'LABEL' || // clicking <a> opens a hyperlink by default
92311                 node.nodeName === 'A');
92312               });
92313               if (isOkayTarget) return; // disable double-tap-to-zoom on touchscreens
92314
92315               d3_event.preventDefault();
92316             });
92317             var detected = utilDetect(); // only WebKit supports gesture events
92318
92319             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
92320             // but we only need to do this on desktop Safari anyway. – #7694
92321             !detected.isMobileWebKit) {
92322               // On iOS we disable pinch-to-zoom of the UI via the `touch-action`
92323               // CSS property, but on desktop Safari we need to manually cancel the
92324               // default gesture events.
92325               container.on('gesturestart.ui gesturechange.ui gestureend.ui', function (d3_event) {
92326                 // disable pinch-to-zoom of the UI via multitouch trackpads on macOS Safari
92327                 d3_event.preventDefault();
92328               });
92329             }
92330
92331             if ('PointerEvent' in window) {
92332               select(window).on('pointerdown.ui pointerup.ui', function (d3_event) {
92333                 var pointerType = d3_event.pointerType || 'mouse';
92334
92335                 if (_lastPointerType !== pointerType) {
92336                   _lastPointerType = pointerType;
92337                   container.attr('pointer', pointerType);
92338                 }
92339               }, true);
92340             } else {
92341               _lastPointerType = 'mouse';
92342               container.attr('pointer', 'mouse');
92343             }
92344
92345             container.attr('lang', _mainLocalizer.localeCode()).attr('dir', _mainLocalizer.textDirection()); // setup fullscreen keybindings (no button shown at this time)
92346
92347             container.call(uiFullScreen(context));
92348             var map = context.map();
92349             map.redrawEnable(false); // don't draw until we've set zoom/lat/long
92350
92351             map.on('hitMinZoom.ui', function () {
92352               ui.flash.iconName('#iD-icon-no').label(_t.html('cannot_zoom'))();
92353             });
92354             container.append('svg').attr('id', 'ideditor-defs').call(ui.svgDefs);
92355             container.append('div').attr('class', 'sidebar').call(ui.sidebar);
92356             var content = container.append('div').attr('class', 'main-content active'); // Top toolbar
92357
92358             content.append('div').attr('class', 'top-toolbar-wrap').append('div').attr('class', 'top-toolbar fillD').call(uiTopToolbar(context));
92359             content.append('div').attr('class', 'main-map').attr('dir', 'ltr').call(map);
92360             var overMap = content.append('div').attr('class', 'over-map'); // HACK: Mobile Safari 14 likes to select anything selectable when long-
92361             // pressing, even if it's not targeted. This conflicts with long-pressing
92362             // to show the edit menu. We add a selectable offscreen element as the first
92363             // child to trick Safari into not showing the selection UI.
92364
92365             overMap.append('div').attr('class', 'select-trap').text('t');
92366             overMap.call(uiMapInMap(context)).call(uiNotice(context));
92367             overMap.append('div').attr('class', 'spinner').call(uiSpinner(context)); // Map controls
92368
92369             var controls = overMap.append('div').attr('class', 'map-controls');
92370             controls.append('div').attr('class', 'map-control zoombuttons').call(uiZoom(context));
92371             controls.append('div').attr('class', 'map-control zoom-to-selection-control').call(uiZoomToSelection(context));
92372             controls.append('div').attr('class', 'map-control geolocate-control').call(uiGeolocate(context)); // Add panes
92373             // This should happen after map is initialized, as some require surface()
92374
92375             var panes = overMap.append('div').attr('class', 'map-panes');
92376             var uiPanes = [uiPaneBackground(context), uiPaneMapData(context), uiPaneIssues(context), uiPanePreferences(context), uiPaneHelp(context)];
92377             uiPanes.forEach(function (pane) {
92378               controls.append('div').attr('class', 'map-control map-pane-control ' + pane.id + '-control').call(pane.renderToggleButton);
92379               panes.call(pane.renderPane);
92380             });
92381             ui.info = uiInfo(context);
92382             overMap.call(ui.info);
92383             overMap.append('div').attr('class', 'photoviewer').classed('al', true) // 'al'=left,  'ar'=right
92384             .classed('hide', true).call(ui.photoviewer);
92385             overMap.append('div').attr('class', 'attribution-wrap').attr('dir', 'ltr').call(uiAttribution(context)); // Add footer
92386
92387             var about = content.append('div').attr('class', 'map-footer');
92388             about.append('div').attr('class', 'api-status').call(uiStatus(context));
92389             var footer = about.append('div').attr('class', 'map-footer-bar fillD');
92390             footer.append('div').attr('class', 'flash-wrap footer-hide');
92391             var footerWrap = footer.append('div').attr('class', 'main-footer-wrap footer-show');
92392             footerWrap.append('div').attr('class', 'scale-block').call(uiScale(context));
92393             var aboutList = footerWrap.append('div').attr('class', 'info-block').append('ul').attr('class', 'map-footer-list');
92394             aboutList.append('li').attr('class', 'user-list').call(uiContributors(context));
92395             var apiConnections = context.apiConnections();
92396
92397             if (apiConnections && apiConnections.length > 1) {
92398               aboutList.append('li').attr('class', 'source-switch').call(uiSourceSwitch(context).keys(apiConnections));
92399             }
92400
92401             aboutList.append('li').attr('class', 'issues-info').call(uiIssuesInfo(context));
92402             aboutList.append('li').attr('class', 'feature-warning').call(uiFeatureInfo(context));
92403             var issueLinks = aboutList.append('li');
92404             issueLinks.append('a').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD/issues').call(svgIcon('#iD-icon-bug', 'light')).call(uiTooltip().title(_t.html('report_a_bug')).placement('top'));
92405             issueLinks.append('a').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD/blob/develop/CONTRIBUTING.md#translating').call(svgIcon('#iD-icon-translate', 'light')).call(uiTooltip().title(_t.html('help_translate')).placement('top'));
92406             aboutList.append('li').attr('class', 'version').call(uiVersion(context));
92407
92408             if (!context.embed()) {
92409               aboutList.call(uiAccount(context));
92410             } // Setup map dimensions and move map to initial center/zoom.
92411             // This should happen after .main-content and toolbars exist.
92412
92413
92414             ui.onResize();
92415             map.redrawEnable(true);
92416             ui.hash = behaviorHash(context);
92417             ui.hash();
92418
92419             if (!ui.hash.hadHash) {
92420               map.centerZoom([0, 0], 2);
92421             } // Bind events
92422
92423
92424             window.onbeforeunload = function () {
92425               return context.save();
92426             };
92427
92428             window.onunload = function () {
92429               context.history().unlock();
92430             };
92431
92432             select(window).on('resize.editor', function () {
92433               ui.onResize();
92434             });
92435             var panPixels = 80;
92436             context.keybinding().on('⌫', function (d3_event) {
92437               d3_event.preventDefault();
92438             }).on([_t('sidebar.key'), '`', '²', '@'], ui.sidebar.toggle) // #5663, #6864 - common QWERTY, AZERTY
92439             .on('←', pan([panPixels, 0])).on('↑', pan([0, panPixels])).on('→', pan([-panPixels, 0])).on('↓', pan([0, -panPixels])).on(uiCmd('⌥←'), pan([map.dimensions()[0], 0])).on(uiCmd('⌥↑'), pan([0, map.dimensions()[1]])).on(uiCmd('⌥→'), pan([-map.dimensions()[0], 0])).on(uiCmd('⌥↓'), pan([0, -map.dimensions()[1]])).on(uiCmd('⌘' + _t('background.key')), function quickSwitch(d3_event) {
92440               if (d3_event) {
92441                 d3_event.stopImmediatePropagation();
92442                 d3_event.preventDefault();
92443               }
92444
92445               var previousBackground = context.background().findSource(corePreferences('background-last-used-toggle'));
92446
92447               if (previousBackground) {
92448                 var currentBackground = context.background().baseLayerSource();
92449                 corePreferences('background-last-used-toggle', currentBackground.id);
92450                 corePreferences('background-last-used', previousBackground.id);
92451                 context.background().baseLayerSource(previousBackground);
92452               }
92453             }).on(_t('area_fill.wireframe.key'), function toggleWireframe(d3_event) {
92454               d3_event.preventDefault();
92455               d3_event.stopPropagation();
92456               context.map().toggleWireframe();
92457             }).on(uiCmd('⌥' + _t('area_fill.wireframe.key')), function toggleOsmData(d3_event) {
92458               d3_event.preventDefault();
92459               d3_event.stopPropagation(); // Don't allow layer changes while drawing - #6584
92460
92461               var mode = context.mode();
92462               if (mode && /^draw/.test(mode.id)) return;
92463               var layer = context.layers().layer('osm');
92464
92465               if (layer) {
92466                 layer.enabled(!layer.enabled());
92467
92468                 if (!layer.enabled()) {
92469                   context.enter(modeBrowse(context));
92470                 }
92471               }
92472             }).on(_t('map_data.highlight_edits.key'), function toggleHighlightEdited(d3_event) {
92473               d3_event.preventDefault();
92474               context.map().toggleHighlightEdited();
92475             });
92476             context.on('enter.editor', function (entered) {
92477               container.classed('mode-' + entered.id, true);
92478             }).on('exit.editor', function (exited) {
92479               container.classed('mode-' + exited.id, false);
92480             });
92481             context.enter(modeBrowse(context));
92482
92483             if (!_initCounter++) {
92484               if (!ui.hash.startWalkthrough) {
92485                 context.container().call(uiSplash(context)).call(uiRestore(context));
92486               }
92487
92488               context.container().call(ui.shortcuts);
92489             }
92490
92491             var osm = context.connection();
92492             var auth = uiLoading(context).message(_t.html('loading_auth')).blocking(true);
92493
92494             if (osm && auth) {
92495               osm.on('authLoading.ui', function () {
92496                 context.container().call(auth);
92497               }).on('authDone.ui', function () {
92498                 auth.close();
92499               });
92500             }
92501
92502             _initCounter++;
92503
92504             if (ui.hash.startWalkthrough) {
92505               ui.hash.startWalkthrough = false;
92506               context.container().call(uiIntro(context));
92507             }
92508
92509             function pan(d) {
92510               return function (d3_event) {
92511                 if (d3_event.shiftKey) return;
92512                 if (context.container().select('.combobox').size()) return;
92513                 d3_event.preventDefault();
92514                 context.map().pan(d, 100);
92515               };
92516             }
92517           }
92518
92519           var ui = {};
92520
92521           var _loadPromise; // renders the iD interface into the container node
92522
92523
92524           ui.ensureLoaded = function () {
92525             if (_loadPromise) return _loadPromise;
92526             return _loadPromise = Promise.all([// must have strings and presets before loading the UI
92527             _mainLocalizer.ensureLoaded(), _mainPresetIndex.ensureLoaded()]).then(function () {
92528               if (!context.container().empty()) render(context.container());
92529             })["catch"](function (err) {
92530               return console.error(err);
92531             }); // eslint-disable-line
92532           }; // `ui.restart()` will destroy and rebuild the entire iD interface,
92533           // for example to switch the locale while iD is running.
92534
92535
92536           ui.restart = function () {
92537             context.keybinding().clear();
92538             _loadPromise = null;
92539             context.container().selectAll('*').remove();
92540             ui.ensureLoaded();
92541           };
92542
92543           ui.lastPointerType = function () {
92544             return _lastPointerType;
92545           };
92546
92547           ui.svgDefs = svgDefs(context);
92548           ui.flash = uiFlash(context);
92549           ui.sidebar = uiSidebar(context);
92550           ui.photoviewer = uiPhotoviewer(context);
92551           ui.shortcuts = uiShortcuts(context);
92552
92553           ui.onResize = function (withPan) {
92554             var map = context.map(); // Recalc dimensions of map and sidebar.. (`true` = force recalc)
92555             // This will call `getBoundingClientRect` and trigger reflow,
92556             //  but the values will be cached for later use.
92557
92558             var mapDimensions = utilGetDimensions(context.container().select('.main-content'), true);
92559             utilGetDimensions(context.container().select('.sidebar'), true);
92560
92561             if (withPan !== undefined) {
92562               map.redrawEnable(false);
92563               map.pan(withPan);
92564               map.redrawEnable(true);
92565             }
92566
92567             map.dimensions(mapDimensions);
92568             ui.photoviewer.onMapResize(); // check if header or footer have overflowed
92569
92570             ui.checkOverflow('.top-toolbar');
92571             ui.checkOverflow('.map-footer-bar'); // Use outdated code so it works on Explorer
92572
92573             var resizeWindowEvent = document.createEvent('Event');
92574             resizeWindowEvent.initEvent('resizeWindow', true, true);
92575             document.dispatchEvent(resizeWindowEvent);
92576           }; // Call checkOverflow when resizing or whenever the contents change.
92577
92578
92579           ui.checkOverflow = function (selector, reset) {
92580             if (reset) {
92581               delete _needWidth[selector];
92582             }
92583
92584             var selection = context.container().select(selector);
92585             if (selection.empty()) return;
92586             var scrollWidth = selection.property('scrollWidth');
92587             var clientWidth = selection.property('clientWidth');
92588             var needed = _needWidth[selector] || scrollWidth;
92589
92590             if (scrollWidth > clientWidth) {
92591               // overflow happening
92592               selection.classed('narrow', true);
92593
92594               if (!_needWidth[selector]) {
92595                 _needWidth[selector] = scrollWidth;
92596               }
92597             } else if (scrollWidth >= needed) {
92598               selection.classed('narrow', false);
92599             }
92600           };
92601
92602           ui.togglePanes = function (showPane) {
92603             var hidePanes = context.container().selectAll('.map-pane.shown');
92604             var side = _mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left';
92605             hidePanes.classed('shown', false).classed('hide', true);
92606             context.container().selectAll('.map-pane-control button').classed('active', false);
92607
92608             if (showPane) {
92609               hidePanes.classed('shown', false).classed('hide', true).style(side, '-500px');
92610               context.container().selectAll('.' + showPane.attr('pane') + '-control button').classed('active', true);
92611               showPane.classed('shown', true).classed('hide', false);
92612
92613               if (hidePanes.empty()) {
92614                 showPane.style(side, '-500px').transition().duration(200).style(side, '0px');
92615               } else {
92616                 showPane.style(side, '0px');
92617               }
92618             } else {
92619               hidePanes.classed('shown', true).classed('hide', false).style(side, '0px').transition().duration(200).style(side, '-500px').on('end', function () {
92620                 select(this).classed('shown', false).classed('hide', true);
92621               });
92622             }
92623           };
92624
92625           var _editMenu = uiEditMenu(context);
92626
92627           ui.editMenu = function () {
92628             return _editMenu;
92629           };
92630
92631           ui.showEditMenu = function (anchorPoint, triggerType, operations) {
92632             // remove any displayed menu
92633             ui.closeEditMenu();
92634             if (!operations && context.mode().operations) operations = context.mode().operations();
92635             if (!operations || !operations.length) return; // disable menu if in wide selection, for example
92636
92637             if (!context.map().editableDataEnabled()) return;
92638             var surfaceNode = context.surface().node();
92639
92640             if (surfaceNode.focus) {
92641               // FF doesn't support it
92642               // focus the surface or else clicking off the menu may not trigger modeBrowse
92643               surfaceNode.focus();
92644             }
92645
92646             operations.forEach(function (operation) {
92647               if (operation.point) operation.point(anchorPoint);
92648             });
92649
92650             _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations); // render the menu
92651
92652
92653             context.map().supersurface.call(_editMenu);
92654           };
92655
92656           ui.closeEditMenu = function () {
92657             // remove any existing menu no matter how it was added
92658             context.map().supersurface.select('.edit-menu').remove();
92659           };
92660
92661           var _saveLoading = select(null);
92662
92663           context.uploader().on('saveStarted.ui', function () {
92664             _saveLoading = uiLoading(context).message(_t.html('save.uploading')).blocking(true);
92665             context.container().call(_saveLoading); // block input during upload
92666           }).on('saveEnded.ui', function () {
92667             _saveLoading.close();
92668
92669             _saveLoading = select(null);
92670           });
92671           return ui;
92672         }
92673
92674         function coreContext() {
92675           var _this = this;
92676
92677           var dispatch = dispatch$8('enter', 'exit', 'change');
92678           var context = utilRebind({}, dispatch, 'on');
92679
92680           var _deferred = new Set();
92681
92682           context.version = '2.20.0';
92683           context.privacyVersion = '20201202'; // iD will alter the hash so cache the parameters intended to setup the session
92684
92685           context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};
92686           context.isFirstSession = !corePreferences('sawSplash') && !corePreferences('sawPrivacyVersion');
92687           /* Changeset */
92688           // An osmChangeset object. Not loaded until needed.
92689
92690           context.changeset = null;
92691           var _defaultChangesetComment = context.initialHashParams.comment;
92692           var _defaultChangesetSource = context.initialHashParams.source;
92693           var _defaultChangesetHashtags = context.initialHashParams.hashtags;
92694
92695           context.defaultChangesetComment = function (val) {
92696             if (!arguments.length) return _defaultChangesetComment;
92697             _defaultChangesetComment = val;
92698             return context;
92699           };
92700
92701           context.defaultChangesetSource = function (val) {
92702             if (!arguments.length) return _defaultChangesetSource;
92703             _defaultChangesetSource = val;
92704             return context;
92705           };
92706
92707           context.defaultChangesetHashtags = function (val) {
92708             if (!arguments.length) return _defaultChangesetHashtags;
92709             _defaultChangesetHashtags = val;
92710             return context;
92711           };
92712           /* Document title */
92713
92714           /* (typically shown as the label for the browser window/tab) */
92715           // If true, iD will update the title based on what the user is doing
92716
92717
92718           var _setsDocumentTitle = true;
92719
92720           context.setsDocumentTitle = function (val) {
92721             if (!arguments.length) return _setsDocumentTitle;
92722             _setsDocumentTitle = val;
92723             return context;
92724           }; // The part of the title that is always the same
92725
92726
92727           var _documentTitleBase = document.title;
92728
92729           context.documentTitleBase = function (val) {
92730             if (!arguments.length) return _documentTitleBase;
92731             _documentTitleBase = val;
92732             return context;
92733           };
92734           /* User interface and keybinding */
92735
92736
92737           var _ui;
92738
92739           context.ui = function () {
92740             return _ui;
92741           };
92742
92743           context.lastPointerType = function () {
92744             return _ui.lastPointerType();
92745           };
92746
92747           var _keybinding = utilKeybinding('context');
92748
92749           context.keybinding = function () {
92750             return _keybinding;
92751           };
92752
92753           select(document).call(_keybinding);
92754           /* Straight accessors. Avoid using these if you can. */
92755           // Instantiate the connection here because it doesn't require passing in
92756           // `context` and it's needed for pre-init calls like `preauth`
92757
92758           var _connection = services.osm;
92759
92760           var _history;
92761
92762           var _validator;
92763
92764           var _uploader;
92765
92766           context.connection = function () {
92767             return _connection;
92768           };
92769
92770           context.history = function () {
92771             return _history;
92772           };
92773
92774           context.validator = function () {
92775             return _validator;
92776           };
92777
92778           context.uploader = function () {
92779             return _uploader;
92780           };
92781           /* Connection */
92782
92783
92784           context.preauth = function (options) {
92785             if (_connection) {
92786               _connection["switch"](options);
92787             }
92788
92789             return context;
92790           };
92791           /* connection options for source switcher (optional) */
92792
92793
92794           var _apiConnections;
92795
92796           context.apiConnections = function (val) {
92797             if (!arguments.length) return _apiConnections;
92798             _apiConnections = val;
92799             return context;
92800           }; // A string or array or locale codes to prefer over the browser's settings
92801
92802
92803           context.locale = function (locale) {
92804             if (!arguments.length) return _mainLocalizer.localeCode();
92805             _mainLocalizer.preferredLocaleCodes(locale);
92806             return context;
92807           };
92808
92809           function afterLoad(cid, callback) {
92810             return function (err, result) {
92811               if (err) {
92812                 // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
92813                 if (err.status === 400 || err.status === 401 || err.status === 403) {
92814                   if (_connection) {
92815                     _connection.logout();
92816                   }
92817                 }
92818
92819                 if (typeof callback === 'function') {
92820                   callback(err);
92821                 }
92822
92823                 return;
92824               } else if (_connection && _connection.getConnectionId() !== cid) {
92825                 if (typeof callback === 'function') {
92826                   callback({
92827                     message: 'Connection Switched',
92828                     status: -1
92829                   });
92830                 }
92831
92832                 return;
92833               } else {
92834                 _history.merge(result.data, result.extent);
92835
92836                 if (typeof callback === 'function') {
92837                   callback(err, result);
92838                 }
92839
92840                 return;
92841               }
92842             };
92843           }
92844
92845           context.loadTiles = function (projection, callback) {
92846             var handle = window.requestIdleCallback(function () {
92847               _deferred["delete"](handle);
92848
92849               if (_connection && context.editableDataEnabled()) {
92850                 var cid = _connection.getConnectionId();
92851
92852                 _connection.loadTiles(projection, afterLoad(cid, callback));
92853               }
92854             });
92855
92856             _deferred.add(handle);
92857           };
92858
92859           context.loadTileAtLoc = function (loc, callback) {
92860             var handle = window.requestIdleCallback(function () {
92861               _deferred["delete"](handle);
92862
92863               if (_connection && context.editableDataEnabled()) {
92864                 var cid = _connection.getConnectionId();
92865
92866                 _connection.loadTileAtLoc(loc, afterLoad(cid, callback));
92867               }
92868             });
92869
92870             _deferred.add(handle);
92871           }; // Download the full entity and its parent relations. The callback may be called multiple times.
92872
92873
92874           context.loadEntity = function (entityID, callback) {
92875             if (_connection) {
92876               var cid = _connection.getConnectionId();
92877
92878               _connection.loadEntity(entityID, afterLoad(cid, callback)); // We need to fetch the parent relations separately.
92879
92880
92881               _connection.loadEntityRelations(entityID, afterLoad(cid, callback));
92882             }
92883           };
92884
92885           context.zoomToEntity = function (entityID, zoomTo) {
92886             // be sure to load the entity even if we're not going to zoom to it
92887             context.loadEntity(entityID, function (err, result) {
92888               if (err) return;
92889
92890               if (zoomTo !== false) {
92891                 var entity = result.data.find(function (e) {
92892                   return e.id === entityID;
92893                 });
92894
92895                 if (entity) {
92896                   _map.zoomTo(entity);
92897                 }
92898               }
92899             });
92900
92901             _map.on('drawn.zoomToEntity', function () {
92902               if (!context.hasEntity(entityID)) return;
92903
92904               _map.on('drawn.zoomToEntity', null);
92905
92906               context.on('enter.zoomToEntity', null);
92907               context.enter(modeSelect(context, [entityID]));
92908             });
92909
92910             context.on('enter.zoomToEntity', function () {
92911               if (_mode.id !== 'browse') {
92912                 _map.on('drawn.zoomToEntity', null);
92913
92914                 context.on('enter.zoomToEntity', null);
92915               }
92916             });
92917           };
92918
92919           var _minEditableZoom = 16;
92920
92921           context.minEditableZoom = function (val) {
92922             if (!arguments.length) return _minEditableZoom;
92923             _minEditableZoom = val;
92924
92925             if (_connection) {
92926               _connection.tileZoom(val);
92927             }
92928
92929             return context;
92930           }; // String length limits in Unicode characters, not JavaScript UTF-16 code units
92931
92932
92933           context.maxCharsForTagKey = function () {
92934             return 255;
92935           };
92936
92937           context.maxCharsForTagValue = function () {
92938             return 255;
92939           };
92940
92941           context.maxCharsForRelationRole = function () {
92942             return 255;
92943           };
92944
92945           function cleanOsmString(val, maxChars) {
92946             // be lenient with input
92947             if (val === undefined || val === null) {
92948               val = '';
92949             } else {
92950               val = val.toString();
92951             } // remove whitespace
92952
92953
92954             val = val.trim(); // use the canonical form of the string
92955
92956             if (val.normalize) val = val.normalize('NFC'); // trim to the number of allowed characters
92957
92958             return utilUnicodeCharsTruncated(val, maxChars);
92959           }
92960
92961           context.cleanTagKey = function (val) {
92962             return cleanOsmString(val, context.maxCharsForTagKey());
92963           };
92964
92965           context.cleanTagValue = function (val) {
92966             return cleanOsmString(val, context.maxCharsForTagValue());
92967           };
92968
92969           context.cleanRelationRole = function (val) {
92970             return cleanOsmString(val, context.maxCharsForRelationRole());
92971           };
92972           /* History */
92973
92974
92975           var _inIntro = false;
92976
92977           context.inIntro = function (val) {
92978             if (!arguments.length) return _inIntro;
92979             _inIntro = val;
92980             return context;
92981           }; // Immediately save the user's history to localstorage, if possible
92982           // This is called someteimes, but also on the `window.onbeforeunload` handler
92983
92984
92985           context.save = function () {
92986             // no history save, no message onbeforeunload
92987             if (_inIntro || context.container().select('.modal').size()) return;
92988             var canSave;
92989
92990             if (_mode && _mode.id === 'save') {
92991               canSave = false; // Attempt to prevent user from creating duplicate changes - see #5200
92992
92993               if (services.osm && services.osm.isChangesetInflight()) {
92994                 _history.clearSaved();
92995
92996                 return;
92997               }
92998             } else {
92999               canSave = context.selectedIDs().every(function (id) {
93000                 var entity = context.hasEntity(id);
93001                 return entity && !entity.isDegenerate();
93002               });
93003             }
93004
93005             if (canSave) {
93006               _history.save();
93007             }
93008
93009             if (_history.hasChanges()) {
93010               return _t('save.unsaved_changes');
93011             }
93012           }; // Debounce save, since it's a synchronous localStorage write,
93013           // and history changes can happen frequently (e.g. when dragging).
93014
93015
93016           context.debouncedSave = debounce(context.save, 350);
93017
93018           function withDebouncedSave(fn) {
93019             return function () {
93020               var result = fn.apply(_history, arguments);
93021               context.debouncedSave();
93022               return result;
93023             };
93024           }
93025           /* Graph */
93026
93027
93028           context.hasEntity = function (id) {
93029             return _history.graph().hasEntity(id);
93030           };
93031
93032           context.entity = function (id) {
93033             return _history.graph().entity(id);
93034           };
93035           /* Modes */
93036
93037
93038           var _mode;
93039
93040           context.mode = function () {
93041             return _mode;
93042           };
93043
93044           context.enter = function (newMode) {
93045             if (_mode) {
93046               _mode.exit();
93047
93048               dispatch.call('exit', _this, _mode);
93049             }
93050
93051             _mode = newMode;
93052
93053             _mode.enter();
93054
93055             dispatch.call('enter', _this, _mode);
93056           };
93057
93058           context.selectedIDs = function () {
93059             return _mode && _mode.selectedIDs && _mode.selectedIDs() || [];
93060           };
93061
93062           context.activeID = function () {
93063             return _mode && _mode.activeID && _mode.activeID();
93064           };
93065
93066           var _selectedNoteID;
93067
93068           context.selectedNoteID = function (noteID) {
93069             if (!arguments.length) return _selectedNoteID;
93070             _selectedNoteID = noteID;
93071             return context;
93072           }; // NOTE: Don't change the name of this until UI v3 is merged
93073
93074
93075           var _selectedErrorID;
93076
93077           context.selectedErrorID = function (errorID) {
93078             if (!arguments.length) return _selectedErrorID;
93079             _selectedErrorID = errorID;
93080             return context;
93081           };
93082           /* Behaviors */
93083
93084
93085           context.install = function (behavior) {
93086             return context.surface().call(behavior);
93087           };
93088
93089           context.uninstall = function (behavior) {
93090             return context.surface().call(behavior.off);
93091           };
93092           /* Copy/Paste */
93093
93094
93095           var _copyGraph;
93096
93097           context.copyGraph = function () {
93098             return _copyGraph;
93099           };
93100
93101           var _copyIDs = [];
93102
93103           context.copyIDs = function (val) {
93104             if (!arguments.length) return _copyIDs;
93105             _copyIDs = val;
93106             _copyGraph = _history.graph();
93107             return context;
93108           };
93109
93110           var _copyLonLat;
93111
93112           context.copyLonLat = function (val) {
93113             if (!arguments.length) return _copyLonLat;
93114             _copyLonLat = val;
93115             return context;
93116           };
93117           /* Background */
93118
93119
93120           var _background;
93121
93122           context.background = function () {
93123             return _background;
93124           };
93125           /* Features */
93126
93127
93128           var _features;
93129
93130           context.features = function () {
93131             return _features;
93132           };
93133
93134           context.hasHiddenConnections = function (id) {
93135             var graph = _history.graph();
93136
93137             var entity = graph.entity(id);
93138             return _features.hasHiddenConnections(entity, graph);
93139           };
93140           /* Photos */
93141
93142
93143           var _photos;
93144
93145           context.photos = function () {
93146             return _photos;
93147           };
93148           /* Map */
93149
93150
93151           var _map;
93152
93153           context.map = function () {
93154             return _map;
93155           };
93156
93157           context.layers = function () {
93158             return _map.layers();
93159           };
93160
93161           context.surface = function () {
93162             return _map.surface;
93163           };
93164
93165           context.editableDataEnabled = function () {
93166             return _map.editableDataEnabled();
93167           };
93168
93169           context.surfaceRect = function () {
93170             return _map.surface.node().getBoundingClientRect();
93171           };
93172
93173           context.editable = function () {
93174             // don't allow editing during save
93175             var mode = context.mode();
93176             if (!mode || mode.id === 'save') return false;
93177             return _map.editableDataEnabled();
93178           };
93179           /* Debug */
93180
93181
93182           var _debugFlags = {
93183             tile: false,
93184             // tile boundaries
93185             collision: false,
93186             // label collision bounding boxes
93187             imagery: false,
93188             // imagery bounding polygons
93189             target: false,
93190             // touch targets
93191             downloaded: false // downloaded data from osm
93192
93193           };
93194
93195           context.debugFlags = function () {
93196             return _debugFlags;
93197           };
93198
93199           context.getDebug = function (flag) {
93200             return flag && _debugFlags[flag];
93201           };
93202
93203           context.setDebug = function (flag, val) {
93204             if (arguments.length === 1) val = true;
93205             _debugFlags[flag] = val;
93206             dispatch.call('change');
93207             return context;
93208           };
93209           /* Container */
93210
93211
93212           var _container = select(null);
93213
93214           context.container = function (val) {
93215             if (!arguments.length) return _container;
93216             _container = val;
93217
93218             _container.classed('ideditor', true);
93219
93220             return context;
93221           };
93222
93223           context.containerNode = function (val) {
93224             if (!arguments.length) return context.container().node();
93225             context.container(select(val));
93226             return context;
93227           };
93228
93229           var _embed;
93230
93231           context.embed = function (val) {
93232             if (!arguments.length) return _embed;
93233             _embed = val;
93234             return context;
93235           };
93236           /* Assets */
93237
93238
93239           var _assetPath = '';
93240
93241           context.assetPath = function (val) {
93242             if (!arguments.length) return _assetPath;
93243             _assetPath = val;
93244             _mainFileFetcher.assetPath(val);
93245             return context;
93246           };
93247
93248           var _assetMap = {};
93249
93250           context.assetMap = function (val) {
93251             if (!arguments.length) return _assetMap;
93252             _assetMap = val;
93253             _mainFileFetcher.assetMap(val);
93254             return context;
93255           };
93256
93257           context.asset = function (val) {
93258             if (/^http(s)?:\/\//i.test(val)) return val;
93259             var filename = _assetPath + val;
93260             return _assetMap[filename] || filename;
93261           };
93262
93263           context.imagePath = function (val) {
93264             return context.asset("img/".concat(val));
93265           };
93266           /* reset (aka flush) */
93267
93268
93269           context.reset = context.flush = function () {
93270             context.debouncedSave.cancel();
93271             Array.from(_deferred).forEach(function (handle) {
93272               window.cancelIdleCallback(handle);
93273
93274               _deferred["delete"](handle);
93275             });
93276             Object.values(services).forEach(function (service) {
93277               if (service && typeof service.reset === 'function') {
93278                 service.reset(context);
93279               }
93280             });
93281             context.changeset = null;
93282
93283             _validator.reset();
93284
93285             _features.reset();
93286
93287             _history.reset();
93288
93289             _uploader.reset(); // don't leave stale state in the inspector
93290
93291
93292             context.container().select('.inspector-wrap *').remove();
93293             return context;
93294           };
93295           /* Projections */
93296
93297
93298           context.projection = geoRawMercator();
93299           context.curtainProjection = geoRawMercator();
93300           /* Init */
93301
93302           context.init = function () {
93303             instantiateInternal();
93304             initializeDependents();
93305             return context; // Load variables and properties. No property of `context` should be accessed
93306             // until this is complete since load statuses are indeterminate. The order
93307             // of instantiation shouldn't matter.
93308
93309             function instantiateInternal() {
93310               _history = coreHistory(context);
93311               context.graph = _history.graph;
93312               context.pauseChangeDispatch = _history.pauseChangeDispatch;
93313               context.resumeChangeDispatch = _history.resumeChangeDispatch;
93314               context.perform = withDebouncedSave(_history.perform);
93315               context.replace = withDebouncedSave(_history.replace);
93316               context.pop = withDebouncedSave(_history.pop);
93317               context.overwrite = withDebouncedSave(_history.overwrite);
93318               context.undo = withDebouncedSave(_history.undo);
93319               context.redo = withDebouncedSave(_history.redo);
93320               _validator = coreValidator(context);
93321               _uploader = coreUploader(context);
93322               _background = rendererBackground(context);
93323               _features = rendererFeatures(context);
93324               _map = rendererMap(context);
93325               _photos = rendererPhotos(context);
93326               _ui = uiInit(context);
93327             } // Set up objects that might need to access properties of `context`. The order
93328             // might matter if dependents make calls to each other. Be wary of async calls.
93329
93330
93331             function initializeDependents() {
93332               if (context.initialHashParams.presets) {
93333                 _mainPresetIndex.addablePresetIDs(new Set(context.initialHashParams.presets.split(',')));
93334               }
93335
93336               if (context.initialHashParams.locale) {
93337                 _mainLocalizer.preferredLocaleCodes(context.initialHashParams.locale);
93338               } // kick off some async work
93339
93340
93341               _mainLocalizer.ensureLoaded();
93342
93343               _background.ensureLoaded();
93344
93345               _mainPresetIndex.ensureLoaded();
93346               Object.values(services).forEach(function (service) {
93347                 if (service && typeof service.init === 'function') {
93348                   service.init();
93349                 }
93350               });
93351
93352               _map.init();
93353
93354               _validator.init();
93355
93356               _features.init();
93357
93358               if (services.maprules && context.initialHashParams.maprules) {
93359                 d3_json(context.initialHashParams.maprules).then(function (mapcss) {
93360                   services.maprules.init();
93361                   mapcss.forEach(function (mapcssSelector) {
93362                     return services.maprules.addRule(mapcssSelector);
93363                   });
93364                 })["catch"](function () {
93365                   /* ignore */
93366                 });
93367               } // if the container isn't available, e.g. when testing, don't load the UI
93368
93369
93370               if (!context.container().empty()) {
93371                 _ui.ensureLoaded().then(function () {
93372                   _photos.init();
93373                 });
93374               }
93375             }
93376           };
93377
93378           return context;
93379         }
93380
93381         // NSI contains the most correct tagging for many commonly mapped features.
93382         // See https://github.com/osmlab/name-suggestion-index  and  https://nsi.guide
93383         // DATA
93384
93385         var _nsiStatus = 'loading'; // 'loading', 'ok', 'failed'
93386
93387         var _nsi = {}; // Sometimes we can upgrade a feature tagged like `building=yes` to a better tag.
93388
93389         var buildingPreset = {
93390           'building/commercial': true,
93391           'building/government': true,
93392           'building/hotel': true,
93393           'building/retail': true,
93394           'building/office': true,
93395           'building/supermarket': true,
93396           'building/yes': true
93397         }; // Exceptions to the namelike regexes.
93398         // Usually a tag suffix contains a language code like `name:en`, `name:ru`
93399         // but we want to exclude things like `operator:type`, `name:etymology`, etc..
93400
93401         var notNames = /:(colou?r|type|forward|backward|left|right|etymology|pronunciation|wikipedia)$/i; // Exceptions to the branchlike regexes
93402
93403         var notBranches = /(coop|express|wireless|factory|outlet)/i; // PRIVATE FUNCTIONS
93404         // `setNsiSources()`
93405         // Adds the sources to iD's filemap so we can start downloading data.
93406         //
93407
93408         function setNsiSources() {
93409           var nsiVersion = packageJSON.devDependencies['name-suggestion-index'];
93410           var v = vparse(nsiVersion);
93411           var vMinor = "".concat(v.major, ".").concat(v.minor);
93412           var sources = {
93413             'nsi_data': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/nsi.min.json"),
93414             'nsi_dissolved': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/dissolved.min.json"),
93415             'nsi_features': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/featureCollection.min.json"),
93416             'nsi_generics': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/genericWords.min.json"),
93417             'nsi_presets': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/presets/nsi-id-presets.min.json"),
93418             'nsi_replacements': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/replacements.min.json"),
93419             'nsi_trees': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/trees.min.json")
93420           };
93421           var fileMap = _mainFileFetcher.fileMap();
93422
93423           for (var k in sources) {
93424             fileMap[k] = sources[k];
93425           }
93426         } // `loadNsiPresets()`
93427         //  Returns a Promise fulfilled when the presets have been downloaded and merged into iD.
93428         //
93429
93430
93431         function loadNsiPresets() {
93432           return Promise.all([_mainFileFetcher.get('nsi_presets'), _mainFileFetcher.get('nsi_features')]).then(function (vals) {
93433             // Add `suggestion=true` to all the nsi presets
93434             // The preset json schema doesn't include it, but the iD code still uses it
93435             Object.values(vals[0].presets).forEach(function (preset) {
93436               return preset.suggestion = true;
93437             });
93438             _mainPresetIndex.merge({
93439               presets: vals[0].presets,
93440               featureCollection: vals[1]
93441             });
93442           });
93443         } // `loadNsiData()`
93444         //  Returns a Promise fulfilled when the other data have been downloaded and processed
93445         //
93446
93447
93448         function loadNsiData() {
93449           return Promise.all([_mainFileFetcher.get('nsi_data'), _mainFileFetcher.get('nsi_dissolved'), _mainFileFetcher.get('nsi_replacements'), _mainFileFetcher.get('nsi_trees')]).then(function (vals) {
93450             _nsi = {
93451               data: vals[0].nsi,
93452               // the raw name-suggestion-index data
93453               dissolved: vals[1].dissolved,
93454               // list of dissolved items
93455               replacements: vals[2].replacements,
93456               // trivial old->new qid replacements
93457               trees: vals[3].trees,
93458               // metadata about trees, main tags
93459               kvt: new Map(),
93460               // Map (k -> Map (v -> t) )
93461               qids: new Map(),
93462               // Map (wd/wp tag values -> qids)
93463               ids: new Map() // Map (id -> NSI item)
93464
93465             };
93466             _nsi.matcher = new Matcher();
93467
93468             _nsi.matcher.buildMatchIndex(_nsi.data);
93469
93470             _nsi.matcher.buildLocationIndex(_nsi.data, _mainLocations.loco());
93471
93472             Object.keys(_nsi.data).forEach(function (tkv) {
93473               var category = _nsi.data[tkv];
93474               var parts = tkv.split('/', 3); // tkv = "tree/key/value"
93475
93476               var t = parts[0];
93477               var k = parts[1];
93478               var v = parts[2]; // Build a reverse index of keys -> values -> trees present in the name-suggestion-index
93479               // Collect primary keys  (e.g. "amenity", "craft", "shop", "man_made", "route", etc)
93480               // "amenity": {
93481               //   "restaurant": "brands"
93482               // }
93483
93484               var vmap = _nsi.kvt.get(k);
93485
93486               if (!vmap) {
93487                 vmap = new Map();
93488
93489                 _nsi.kvt.set(k, vmap);
93490               }
93491
93492               vmap.set(v, t);
93493               var tree = _nsi.trees[t]; // e.g. "brands", "operators"
93494
93495               var mainTag = tree.mainTag; // e.g. "brand:wikidata", "operator:wikidata", etc
93496
93497               var items = category.items || [];
93498               items.forEach(function (item) {
93499                 // Remember some useful things for later, cache NSI id -> item
93500                 item.tkv = tkv;
93501                 item.mainTag = mainTag;
93502
93503                 _nsi.ids.set(item.id, item); // Cache Wikidata/Wikipedia values -> qid, for #6416
93504
93505
93506                 var wd = item.tags[mainTag];
93507                 var wp = item.tags[mainTag.replace('wikidata', 'wikipedia')];
93508                 if (wd) _nsi.qids.set(wd, wd);
93509                 if (wp && wd) _nsi.qids.set(wp, wd);
93510               });
93511             });
93512           });
93513         } // `gatherKVs()`
93514         // Gather all the k/v pairs that we will run through the NSI matcher.
93515         // An OSM tags object can contain anything, but only a few tags will be interesting to NSI.
93516         //
93517         // This function will return the interesting tag pairs like:
93518         //   "amenity/restaurant", "man_made/flagpole"
93519         // and fallbacks like
93520         //   "amenity/yes"
93521         // excluding things like
93522         //   "highway", "surface", "ref", etc.
93523         //
93524         // Arguments
93525         //   `tags`: `Object` containing the feature's OSM tags
93526         // Returns
93527         //   `Object` containing kv pairs to test:
93528         //   {
93529         //     'primary': Set(),
93530         //     'alternate': Set()
93531         //   }
93532         //
93533
93534
93535         function gatherKVs(tags) {
93536           var primary = new Set();
93537           var alternate = new Set();
93538           Object.keys(tags).forEach(function (osmkey) {
93539             var osmvalue = tags[osmkey];
93540             if (!osmvalue) return;
93541
93542             var vmap = _nsi.kvt.get(osmkey);
93543
93544             if (!vmap) return;
93545
93546             if (osmvalue !== 'yes') {
93547               primary.add("".concat(osmkey, "/").concat(osmvalue));
93548             } else {
93549               alternate.add("".concat(osmkey, "/").concat(osmvalue));
93550             }
93551           }); // Can we try a generic building fallback match? - See #6122, #7197
93552           // Only try this if we do a preset match and find nothing else remarkable about that building.
93553           // For example, a way with `building=yes` + `name=Westfield` may be a Westfield department store.
93554           // But a way with `building=yes` + `name=Westfield` + `public_transport=station` is a train station for a town named "Westfield"
93555
93556           var preset = _mainPresetIndex.matchTags(tags, 'area');
93557
93558           if (buildingPreset[preset.id]) {
93559             alternate.add('building/yes');
93560           }
93561
93562           return {
93563             primary: primary,
93564             alternate: alternate
93565           };
93566         } // `identifyTree()`
93567         // NSI has a concept of trees: "brands", "operators", "flags", "transit".
93568         // The tree determines things like which tags are namelike, and which tags hold important wikidata.
93569         // This takes an Object of tags and tries to identify what tree to use.
93570         //
93571         // Arguments
93572         //   `tags`: `Object` containing the feature's OSM tags
93573         // Returns
93574         //   `string` the name of the tree if known
93575         //   or 'unknown' if it could match several trees (e.g. amenity/yes)
93576         //   or null if no match
93577         //
93578
93579
93580         function identifyTree(tags) {
93581           var unknown;
93582           var t; // Check all tags
93583
93584           Object.keys(tags).forEach(function (osmkey) {
93585             if (t) return; // found already
93586
93587             var osmvalue = tags[osmkey];
93588             if (!osmvalue) return;
93589
93590             var vmap = _nsi.kvt.get(osmkey);
93591
93592             if (!vmap) return; // this key is not in nsi
93593
93594             if (osmvalue === 'yes') {
93595               unknown = 'unknown';
93596             } else {
93597               t = vmap.get(osmvalue);
93598             }
93599           });
93600           return t || unknown || null;
93601         } // `gatherNames()`
93602         // Gather all the namelike values that we will run through the NSI matcher.
93603         // It will gather values primarily from tags `name`, `name:ru`, `flag:name`
93604         //  and fallback to alternate tags like `brand`, `brand:ru`, `alt_name`
93605         //
93606         // Arguments
93607         //   `tags`: `Object` containing the feature's OSM tags
93608         // Returns
93609         //   `Object` containing namelike values to test:
93610         //   {
93611         //     'primary': Set(),
93612         //     'fallbacks': Set()
93613         //   }
93614         //
93615
93616
93617         function gatherNames(tags) {
93618           var empty = {
93619             primary: new Set(),
93620             alternate: new Set()
93621           };
93622           var primary = new Set();
93623           var alternate = new Set();
93624           var foundSemi = false;
93625           var testNameFragments = false;
93626           var patterns; // Patterns for matching OSM keys that might contain namelike values.
93627           // These roughly correspond to the "trees" concept in name-suggestion-index,
93628
93629           var t = identifyTree(tags);
93630           if (!t) return empty;
93631
93632           if (t === 'transit') {
93633             patterns = {
93634               primary: /^network$/i,
93635               alternate: /^(operator|operator:\w+|network:\w+|\w+_name|\w+_name:\w+)$/i
93636             };
93637           } else if (t === 'flags') {
93638             patterns = {
93639               primary: /^(flag:name|flag:name:\w+)$/i,
93640               alternate: /^(flag|flag:\w+|subject|subject:\w+)$/i // note: no `country`, we special-case it below
93641
93642             };
93643           } else if (t === 'brands') {
93644             testNameFragments = true;
93645             patterns = {
93646               primary: /^(name|name:\w+)$/i,
93647               alternate: /^(brand|brand:\w+|operator|operator:\w+|\w+_name|\w+_name:\w+)/i
93648             };
93649           } else if (t === 'operators') {
93650             testNameFragments = true;
93651             patterns = {
93652               primary: /^(name|name:\w+|operator|operator:\w+)$/i,
93653               alternate: /^(brand|brand:\w+|\w+_name|\w+_name:\w+)/i
93654             };
93655           } else {
93656             // unknown/multiple
93657             testNameFragments = true;
93658             patterns = {
93659               primary: /^(name|name:\w+)$/i,
93660               alternate: /^(brand|brand:\w+|network|network:\w+|operator|operator:\w+|\w+_name|\w+_name:\w+)/i
93661             };
93662           } // Test `name` fragments, longest to shortest, to fit them into a "Name Branch" pattern.
93663           // e.g. "TUI ReiseCenter - Neuss Innenstadt" -> ["TUI", "ReiseCenter", "Neuss", "Innenstadt"]
93664
93665
93666           if (tags.name && testNameFragments) {
93667             var nameParts = tags.name.split(/[\s\-\/,.]/);
93668
93669             for (var split = nameParts.length; split > 0; split--) {
93670               var name = nameParts.slice(0, split).join(' '); // e.g. "TUI ReiseCenter"
93671
93672               primary.add(name);
93673             }
93674           } // Check all tags
93675
93676
93677           Object.keys(tags).forEach(function (osmkey) {
93678             var osmvalue = tags[osmkey];
93679             if (!osmvalue) return;
93680
93681             if (isNamelike(osmkey, 'primary')) {
93682               if (/;/.test(osmvalue)) {
93683                 foundSemi = true;
93684               } else {
93685                 primary.add(osmvalue);
93686                 alternate["delete"](osmvalue);
93687               }
93688             } else if (!primary.has(osmvalue) && isNamelike(osmkey, 'alternate')) {
93689               if (/;/.test(osmvalue)) {
93690                 foundSemi = true;
93691               } else {
93692                 alternate.add(osmvalue);
93693               }
93694             }
93695           }); // For flags only, fallback to `country` tag only if no other namelike values were found.
93696           // See https://github.com/openstreetmap/iD/pull/8305#issuecomment-769174070
93697
93698           if (tags.man_made === 'flagpole' && !primary.size && !alternate.size && !!tags.country) {
93699             var osmvalue = tags.country;
93700
93701             if (/;/.test(osmvalue)) {
93702               foundSemi = true;
93703             } else {
93704               alternate.add(osmvalue);
93705             }
93706           } // If any namelike value contained a semicolon, return empty set and don't try matching anything.
93707
93708
93709           if (foundSemi) {
93710             return empty;
93711           } else {
93712             return {
93713               primary: primary,
93714               alternate: alternate
93715             };
93716           }
93717
93718           function isNamelike(osmkey, which) {
93719             return patterns[which].test(osmkey) && !notNames.test(osmkey);
93720           }
93721         } // `gatherTuples()`
93722         // Generate all combinations of [key,value,name] that we want to test.
93723         // This prioritizes them so that the primary name and k/v pairs go first
93724         //
93725         // Arguments
93726         //   `tryKVs`: `Object` containing primary and alternate k/v pairs to test
93727         //   `tryNames`: `Object` containing primary and alternate names to test
93728         // Returns
93729         //   `Array`: tuple objects ordered by priority
93730         //
93731
93732
93733         function gatherTuples(tryKVs, tryNames) {
93734           var tuples = [];
93735           ['primary', 'alternate'].forEach(function (whichName) {
93736             // test names longest to shortest
93737             var arr = Array.from(tryNames[whichName]).sort(function (a, b) {
93738               return b.length - a.length;
93739             });
93740             arr.forEach(function (n) {
93741               ['primary', 'alternate'].forEach(function (whichKV) {
93742                 tryKVs[whichKV].forEach(function (kv) {
93743                   var parts = kv.split('/', 2);
93744                   var k = parts[0];
93745                   var v = parts[1];
93746                   tuples.push({
93747                     k: k,
93748                     v: v,
93749                     n: n
93750                   });
93751                 });
93752               });
93753             });
93754           });
93755           return tuples;
93756         } // `_upgradeTags()`
93757         // Try to match a feature to a canonical record in name-suggestion-index
93758         // and upgrade the tags to match.
93759         //
93760         // Arguments
93761         //   `tags`: `Object` containing the feature's OSM tags
93762         //   `loc`: Location where this feature exists, as a [lon, lat]
93763         // Returns
93764         //   `Object`: The tags the the feature should have, or `null` if no changes needed
93765         //
93766
93767
93768         function _upgradeTags(tags, loc) {
93769           var newTags = Object.assign({}, tags); // shallow copy
93770
93771           var changed = false; // Before anything, perform trivial Wikipedia/Wikidata replacements
93772
93773           Object.keys(newTags).forEach(function (osmkey) {
93774             var matchTag = osmkey.match(/^(\w+:)?wikidata$/);
93775
93776             if (matchTag) {
93777               // Look at '*:wikidata' tags
93778               var prefix = matchTag[1] || '';
93779               var wd = newTags[osmkey];
93780               var replace = _nsi.replacements[wd]; // If it matches a QID in the replacement list...
93781
93782               if (replace && replace.wikidata !== undefined) {
93783                 // replace or delete `*:wikidata` tag
93784                 changed = true;
93785
93786                 if (replace.wikidata) {
93787                   newTags[osmkey] = replace.wikidata;
93788                 } else {
93789                   delete newTags[osmkey];
93790                 }
93791               }
93792
93793               if (replace && replace.wikipedia !== undefined) {
93794                 // replace or delete `*:wikipedia` tag
93795                 changed = true;
93796                 var wpkey = "".concat(prefix, "wikipedia");
93797
93798                 if (replace.wikipedia) {
93799                   newTags[wpkey] = replace.wikipedia;
93800                 } else {
93801                   delete newTags[wpkey];
93802                 }
93803               }
93804             }
93805           }); // Gather key/value tag pairs to try to match
93806
93807           var tryKVs = gatherKVs(tags);
93808           if (!tryKVs.primary.size && !tryKVs.alternate.size) return changed ? newTags : null; // Gather namelike tag values to try to match
93809
93810           var tryNames = gatherNames(tags); // Do `wikidata=*` or `wikipedia=*` tags identify this entity as a chain? - See #6416
93811           // If so, these tags can be swapped to e.g. `brand:wikidata`/`brand:wikipedia`.
93812
93813           var foundQID = _nsi.qids.get(tags.wikidata) || _nsi.qids.get(tags.wikipedia);
93814
93815           if (foundQID) tryNames.primary.add(foundQID); // matcher will recognize the Wikidata QID as name too
93816
93817           if (!tryNames.primary.size && !tryNames.alternate.size) return changed ? newTags : null; // Order the [key,value,name] tuples - test primary before alternate
93818
93819           var tuples = gatherTuples(tryKVs, tryNames);
93820
93821           var _loop = function _loop(i) {
93822             var tuple = tuples[i];
93823
93824             var hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n, loc); // Attempt to match an item in NSI
93825
93826
93827             if (!hits || !hits.length) return "continue"; // no match, try next tuple
93828
93829             if (hits[0].match !== 'primary' && hits[0].match !== 'alternate') return "break"; // a generic match, stop looking
93830             // A match may contain multiple results, the first one is likely the best one for this location
93831             // e.g. `['pfk-a54c14', 'kfc-1ff19c', 'kfc-658eea']`
93832
93833             var itemID = void 0,
93834                 item = void 0;
93835
93836             for (var j = 0; j < hits.length; j++) {
93837               var hit = hits[j];
93838               itemID = hit.itemID;
93839               if (_nsi.dissolved[itemID]) continue; // Don't upgrade to a dissolved item
93840
93841               item = _nsi.ids.get(itemID);
93842               if (!item) continue;
93843               var mainTag = item.mainTag; // e.g. `brand:wikidata`
93844
93845               var itemQID = item.tags[mainTag]; // e.g. `brand:wikidata` qid
93846
93847               var notQID = newTags["not:".concat(mainTag)]; // e.g. `not:brand:wikidata` qid
93848
93849               if ( // Exceptions, skip this hit
93850               !itemQID || itemQID === notQID || // No `*:wikidata` or matched a `not:*:wikidata`
93851               newTags.office && !item.tags.office // feature may be a corporate office for a brand? - #6416
93852               ) {
93853                   item = null;
93854                   continue; // continue looking
93855                 } else {
93856                   break; // use `item`
93857                 }
93858             } // Can't use any of these hits, try next tuple..
93859
93860
93861             if (!item) return "continue"; // At this point we have matched a canonical item and can suggest tag upgrades..
93862
93863             var tkv = item.tkv;
93864             var parts = tkv.split('/', 3); // tkv = "tree/key/value"
93865
93866             var k = parts[1];
93867             var v = parts[2];
93868             var category = _nsi.data[tkv];
93869             var properties = category.properties || {}; // Preserve some tags that we specifically don't want NSI to overwrite. ('^name', sometimes)
93870
93871             var preserveTags = item.preserveTags || properties.preserveTags || [];
93872             var regexes = preserveTags.map(function (s) {
93873               return new RegExp(s, 'i');
93874             });
93875             regexes.push(/^building$/i, /^takeaway$/i);
93876             var keepTags = {};
93877             Object.keys(newTags).forEach(function (osmkey) {
93878               if (regexes.some(function (regex) {
93879                 return regex.test(osmkey);
93880               })) {
93881                 keepTags[osmkey] = newTags[osmkey];
93882               }
93883             }); // Remove any primary tags ("amenity", "craft", "shop", "man_made", "route", etc)
93884             // with a value like `amenity=yes` or `shop=yes`
93885
93886             _nsi.kvt.forEach(function (vmap, k) {
93887               if (newTags[k] === 'yes') delete newTags[k];
93888             }); // Replace mistagged `wikidata`/`wikipedia` with e.g. `brand:wikidata`/`brand:wikipedia`
93889
93890
93891             if (foundQID) {
93892               delete newTags.wikipedia;
93893               delete newTags.wikidata;
93894             } // Do the tag upgrade
93895
93896
93897             Object.assign(newTags, item.tags, keepTags); // Special `branch` splitting rules - IF..
93898             // - NSI is suggesting to replace `name`, AND
93899             // - `branch` doesn't already contain something, AND
93900             // - original name has not moved to an alternate name (e.g. "Dunkin' Donuts" -> "Dunkin'"), AND
93901             // - original name is "some name" + "some stuff", THEN
93902             // consider splitting `name` into `name`/`branch`..
93903
93904             var origName = tags.name;
93905             var newName = newTags.name;
93906
93907             if (newName && origName && newName !== origName && !newTags.branch) {
93908               var newNames = gatherNames(newTags);
93909               var newSet = new Set([].concat(_toConsumableArray(newNames.primary), _toConsumableArray(newNames.alternate)));
93910               var isMoved = newSet.has(origName); // another tag holds the original name now
93911
93912               if (!isMoved) {
93913                 // Test name fragments, longest to shortest, to fit them into a "Name Branch" pattern.
93914                 // e.g. "TUI ReiseCenter - Neuss Innenstadt" -> ["TUI", "ReiseCenter", "Neuss", "Innenstadt"]
93915                 var nameParts = origName.split(/[\s\-\/,.]/);
93916
93917                 for (var split = nameParts.length; split > 0; split--) {
93918                   var name = nameParts.slice(0, split).join(' '); // e.g. "TUI ReiseCenter"
93919
93920                   var branch = nameParts.slice(split).join(' '); // e.g. "Neuss Innenstadt"
93921
93922                   var nameHits = _nsi.matcher.match(k, v, name, loc);
93923
93924                   if (!nameHits || !nameHits.length) continue; // no match, try next name fragment
93925
93926                   if (nameHits.some(function (hit) {
93927                     return hit.itemID === itemID;
93928                   })) {
93929                     // matched the name fragment to the same itemID above
93930                     if (branch) {
93931                       if (notBranches.test(branch)) {
93932                         // "branch" was detected but is noise ("factory outlet", etc)
93933                         newTags.name = origName; // Leave `name` alone, this part of the name may be significant..
93934                       } else {
93935                         var branchHits = _nsi.matcher.match(k, v, branch, loc);
93936
93937                         if (branchHits && branchHits.length) {
93938                           // if "branch" matched something else in NSI..
93939                           if (branchHits[0].match === 'primary' || branchHits[0].match === 'alternate') {
93940                             // if another brand! (e.g. "KFC - Taco Bell"?)
93941                             return {
93942                               v: null
93943                             }; //   bail out - can't suggest tags in this case
93944                           } // else a generic (e.g. "gas", "cafe") - ignore
93945
93946                         } else {
93947                           // "branch" is not noise and not something in NSI
93948                           newTags.branch = branch; // Stick it in the `branch` tag..
93949                         }
93950                       }
93951                     }
93952
93953                     break;
93954                   }
93955                 }
93956               }
93957             }
93958
93959             return {
93960               v: newTags
93961             };
93962           };
93963
93964           for (var i = 0; i < tuples.length; i++) {
93965             var _ret = _loop(i);
93966
93967             if (_ret === "continue") continue;
93968             if (_ret === "break") break;
93969             if (_typeof(_ret) === "object") return _ret.v;
93970           }
93971
93972           return changed ? newTags : null;
93973         } // `_isGenericName()`
93974         // Is the `name` tag generic?
93975         //
93976         // Arguments
93977         //   `tags`: `Object` containing the feature's OSM tags
93978         // Returns
93979         //   `true` if it is generic, `false` if not
93980         //
93981
93982
93983         function _isGenericName(tags) {
93984           var n = tags.name;
93985           if (!n) return false; // tryNames just contains the `name` tag value and nothing else
93986
93987           var tryNames = {
93988             primary: new Set([n]),
93989             alternate: new Set()
93990           }; // Gather key/value tag pairs to try to match
93991
93992           var tryKVs = gatherKVs(tags);
93993           if (!tryKVs.primary.size && !tryKVs.alternate.size) return false; // Order the [key,value,name] tuples - test primary before alternate
93994
93995           var tuples = gatherTuples(tryKVs, tryNames);
93996
93997           for (var i = 0; i < tuples.length; i++) {
93998             var tuple = tuples[i];
93999
94000             var hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n); // Attempt to match an item in NSI
94001             // If we get a `excludeGeneric` hit, this is a generic name.
94002
94003
94004             if (hits && hits.length && hits[0].match === 'excludeGeneric') return true;
94005           }
94006
94007           return false;
94008         } // PUBLIC INTERFACE
94009
94010
94011         var serviceNsi = {
94012           // `init()`
94013           // On init, start preparing the name-suggestion-index
94014           //
94015           init: function init() {
94016             // Note: service.init is called immediately after the presetManager has started loading its data.
94017             // We expect to chain onto an unfulfilled promise here.
94018             setNsiSources();
94019             _mainPresetIndex.ensureLoaded().then(function () {
94020               return loadNsiPresets();
94021             }).then(function () {
94022               return delay(100);
94023             }) // wait briefly for locationSets to enter the locationManager queue
94024             .then(function () {
94025               return _mainLocations.mergeLocationSets([]);
94026             }) // wait for locationSets to resolve
94027             .then(function () {
94028               return loadNsiData();
94029             }).then(function () {
94030               return _nsiStatus = 'ok';
94031             })["catch"](function () {
94032               return _nsiStatus = 'failed';
94033             });
94034
94035             function delay(msec) {
94036               return new Promise(function (resolve) {
94037                 window.setTimeout(resolve, msec);
94038               });
94039             }
94040           },
94041           // `reset()`
94042           // Reset is called when user saves data to OSM (does nothing here)
94043           //
94044           reset: function reset() {},
94045           // `status()`
94046           // To let other code know how it's going...
94047           //
94048           // Returns
94049           //   `String`: 'loading', 'ok', 'failed'
94050           //
94051           status: function status() {
94052             return _nsiStatus;
94053           },
94054           // `isGenericName()`
94055           // Is the `name` tag generic?
94056           //
94057           // Arguments
94058           //   `tags`: `Object` containing the feature's OSM tags
94059           // Returns
94060           //   `true` if it is generic, `false` if not
94061           //
94062           isGenericName: function isGenericName(tags) {
94063             return _isGenericName(tags);
94064           },
94065           // `upgradeTags()`
94066           // Suggest tag upgrades.
94067           // This function will not modify the input tags, it makes a copy.
94068           //
94069           // Arguments
94070           //   `tags`: `Object` containing the feature's OSM tags
94071           //   `loc`: Location where this feature exists, as a [lon, lat]
94072           // Returns
94073           //   `Object`: The tags the the feature should have, or `null` if no change
94074           //
94075           upgradeTags: function upgradeTags(tags, loc) {
94076             return _upgradeTags(tags, loc);
94077           },
94078           // `cache()`
94079           // Direct access to the NSI cache, useful for testing or breaking things
94080           //
94081           // Returns
94082           //   `Object`: the internal NSI cache
94083           //
94084           cache: function cache() {
94085             return _nsi;
94086           }
94087         };
94088
94089         var apibase$1 = 'https://openstreetcam.org';
94090         var maxResults$1 = 1000;
94091         var tileZoom$1 = 14;
94092         var tiler$3 = utilTiler().zoomExtent([tileZoom$1, tileZoom$1]).skipNullIsland(true);
94093         var dispatch$3 = dispatch$8('loadedImages');
94094         var imgZoom = d3_zoom().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
94095
94096         var _oscCache;
94097
94098         var _oscSelectedImage;
94099
94100         var _loadViewerPromise$1;
94101
94102         function abortRequest$3(controller) {
94103           controller.abort();
94104         }
94105
94106         function maxPageAtZoom(z) {
94107           if (z < 15) return 2;
94108           if (z === 15) return 5;
94109           if (z === 16) return 10;
94110           if (z === 17) return 20;
94111           if (z === 18) return 40;
94112           if (z > 18) return 80;
94113         }
94114
94115         function loadTiles$1(which, url, projection) {
94116           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
94117           var tiles = tiler$3.getTiles(projection); // abort inflight requests that are no longer needed
94118
94119           var cache = _oscCache[which];
94120           Object.keys(cache.inflight).forEach(function (k) {
94121             var wanted = tiles.find(function (tile) {
94122               return k.indexOf(tile.id + ',') === 0;
94123             });
94124
94125             if (!wanted) {
94126               abortRequest$3(cache.inflight[k]);
94127               delete cache.inflight[k];
94128             }
94129           });
94130           tiles.forEach(function (tile) {
94131             loadNextTilePage$1(which, currZoom, url, tile);
94132           });
94133         }
94134
94135         function loadNextTilePage$1(which, currZoom, url, tile) {
94136           var cache = _oscCache[which];
94137           var bbox = tile.extent.bbox();
94138           var maxPages = maxPageAtZoom(currZoom);
94139           var nextPage = cache.nextPage[tile.id] || 1;
94140           var params = utilQsString({
94141             ipp: maxResults$1,
94142             page: nextPage,
94143             // client_id: clientId,
94144             bbTopLeft: [bbox.maxY, bbox.minX].join(','),
94145             bbBottomRight: [bbox.minY, bbox.maxX].join(',')
94146           }, true);
94147           if (nextPage > maxPages) return;
94148           var id = tile.id + ',' + String(nextPage);
94149           if (cache.loaded[id] || cache.inflight[id]) return;
94150           var controller = new AbortController();
94151           cache.inflight[id] = controller;
94152           var options = {
94153             method: 'POST',
94154             signal: controller.signal,
94155             body: params,
94156             headers: {
94157               'Content-Type': 'application/x-www-form-urlencoded'
94158             }
94159           };
94160           d3_json(url, options).then(function (data) {
94161             cache.loaded[id] = true;
94162             delete cache.inflight[id];
94163
94164             if (!data || !data.currentPageItems || !data.currentPageItems.length) {
94165               throw new Error('No Data');
94166             }
94167
94168             var features = data.currentPageItems.map(function (item) {
94169               var loc = [+item.lng, +item.lat];
94170               var d;
94171
94172               if (which === 'images') {
94173                 d = {
94174                   loc: loc,
94175                   key: item.id,
94176                   ca: +item.heading,
94177                   captured_at: item.shot_date || item.date_added,
94178                   captured_by: item.username,
94179                   imagePath: item.lth_name,
94180                   sequence_id: item.sequence_id,
94181                   sequence_index: +item.sequence_index
94182                 }; // cache sequence info
94183
94184                 var seq = _oscCache.sequences[d.sequence_id];
94185
94186                 if (!seq) {
94187                   seq = {
94188                     rotation: 0,
94189                     images: []
94190                   };
94191                   _oscCache.sequences[d.sequence_id] = seq;
94192                 }
94193
94194                 seq.images[d.sequence_index] = d;
94195                 _oscCache.images.forImageKey[d.key] = d; // cache imageKey -> image
94196               }
94197
94198               return {
94199                 minX: loc[0],
94200                 minY: loc[1],
94201                 maxX: loc[0],
94202                 maxY: loc[1],
94203                 data: d
94204               };
94205             });
94206             cache.rtree.load(features);
94207
94208             if (data.currentPageItems.length === maxResults$1) {
94209               // more pages to load
94210               cache.nextPage[tile.id] = nextPage + 1;
94211               loadNextTilePage$1(which, currZoom, url, tile);
94212             } else {
94213               cache.nextPage[tile.id] = Infinity; // no more pages to load
94214             }
94215
94216             if (which === 'images') {
94217               dispatch$3.call('loadedImages');
94218             }
94219           })["catch"](function () {
94220             cache.loaded[id] = true;
94221             delete cache.inflight[id];
94222           });
94223         } // partition viewport into higher zoom tiles
94224
94225
94226         function partitionViewport$1(projection) {
94227           var z = geoScaleToZoom(projection.scale());
94228           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
94229
94230           var tiler = utilTiler().zoomExtent([z2, z2]);
94231           return tiler.getTiles(projection).map(function (tile) {
94232             return tile.extent;
94233           });
94234         } // no more than `limit` results per partition.
94235
94236
94237         function searchLimited$1(limit, projection, rtree) {
94238           limit = limit || 5;
94239           return partitionViewport$1(projection).reduce(function (result, extent) {
94240             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
94241               return d.data;
94242             });
94243             return found.length ? result.concat(found) : result;
94244           }, []);
94245         }
94246
94247         var serviceOpenstreetcam = {
94248           init: function init() {
94249             if (!_oscCache) {
94250               this.reset();
94251             }
94252
94253             this.event = utilRebind(this, dispatch$3, 'on');
94254           },
94255           reset: function reset() {
94256             if (_oscCache) {
94257               Object.values(_oscCache.images.inflight).forEach(abortRequest$3);
94258             }
94259
94260             _oscCache = {
94261               images: {
94262                 inflight: {},
94263                 loaded: {},
94264                 nextPage: {},
94265                 rtree: new RBush(),
94266                 forImageKey: {}
94267               },
94268               sequences: {}
94269             };
94270             _oscSelectedImage = null;
94271           },
94272           images: function images(projection) {
94273             var limit = 5;
94274             return searchLimited$1(limit, projection, _oscCache.images.rtree);
94275           },
94276           sequences: function sequences(projection) {
94277             var viewport = projection.clipExtent();
94278             var min = [viewport[0][0], viewport[1][1]];
94279             var max = [viewport[1][0], viewport[0][1]];
94280             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
94281             var sequenceKeys = {}; // all sequences for images in viewport
94282
94283             _oscCache.images.rtree.search(bbox).forEach(function (d) {
94284               sequenceKeys[d.data.sequence_id] = true;
94285             }); // make linestrings from those sequences
94286
94287
94288             var lineStrings = [];
94289             Object.keys(sequenceKeys).forEach(function (sequenceKey) {
94290               var seq = _oscCache.sequences[sequenceKey];
94291               var images = seq && seq.images;
94292
94293               if (images) {
94294                 lineStrings.push({
94295                   type: 'LineString',
94296                   coordinates: images.map(function (d) {
94297                     return d.loc;
94298                   }).filter(Boolean),
94299                   properties: {
94300                     captured_at: images[0] ? images[0].captured_at : null,
94301                     captured_by: images[0] ? images[0].captured_by : null,
94302                     key: sequenceKey
94303                   }
94304                 });
94305               }
94306             });
94307             return lineStrings;
94308           },
94309           cachedImage: function cachedImage(imageKey) {
94310             return _oscCache.images.forImageKey[imageKey];
94311           },
94312           loadImages: function loadImages(projection) {
94313             var url = apibase$1 + '/1.0/list/nearby-photos/';
94314             loadTiles$1('images', url, projection);
94315           },
94316           ensureViewerLoaded: function ensureViewerLoaded(context) {
94317             if (_loadViewerPromise$1) return _loadViewerPromise$1; // add osc-wrapper
94318
94319             var wrap = context.container().select('.photoviewer').selectAll('.osc-wrapper').data([0]);
94320             var that = this;
94321             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper osc-wrapper').classed('hide', true).call(imgZoom.on('zoom', zoomPan)).on('dblclick.zoom', null);
94322             wrapEnter.append('div').attr('class', 'photo-attribution fillD');
94323             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
94324             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
94325             controlsEnter.append('button').on('click.rotate-ccw', rotate(-90)).html('⤿');
94326             controlsEnter.append('button').on('click.rotate-cw', rotate(90)).html('⤾');
94327             controlsEnter.append('button').on('click.forward', step(1)).html('►');
94328             wrapEnter.append('div').attr('class', 'osc-image-wrap'); // Register viewer resize handler
94329
94330             context.ui().photoviewer.on('resize.openstreetcam', function (dimensions) {
94331               imgZoom = d3_zoom().extent([[0, 0], dimensions]).translateExtent([[0, 0], dimensions]).scaleExtent([1, 15]).on('zoom', zoomPan);
94332             });
94333
94334             function zoomPan(d3_event) {
94335               var t = d3_event.transform;
94336               context.container().select('.photoviewer .osc-image-wrap').call(utilSetTransform, t.x, t.y, t.k);
94337             }
94338
94339             function rotate(deg) {
94340               return function () {
94341                 if (!_oscSelectedImage) return;
94342                 var sequenceKey = _oscSelectedImage.sequence_id;
94343                 var sequence = _oscCache.sequences[sequenceKey];
94344                 if (!sequence) return;
94345                 var r = sequence.rotation || 0;
94346                 r += deg;
94347                 if (r > 180) r -= 360;
94348                 if (r < -180) r += 360;
94349                 sequence.rotation = r;
94350                 var wrap = context.container().select('.photoviewer .osc-wrapper');
94351                 wrap.transition().duration(100).call(imgZoom.transform, identity$2);
94352                 wrap.selectAll('.osc-image').transition().duration(100).style('transform', 'rotate(' + r + 'deg)');
94353               };
94354             }
94355
94356             function step(stepBy) {
94357               return function () {
94358                 if (!_oscSelectedImage) return;
94359                 var sequenceKey = _oscSelectedImage.sequence_id;
94360                 var sequence = _oscCache.sequences[sequenceKey];
94361                 if (!sequence) return;
94362                 var nextIndex = _oscSelectedImage.sequence_index + stepBy;
94363                 var nextImage = sequence.images[nextIndex];
94364                 if (!nextImage) return;
94365                 context.map().centerEase(nextImage.loc);
94366                 that.selectImage(context, nextImage.key);
94367               };
94368             } // don't need any async loading so resolve immediately
94369
94370
94371             _loadViewerPromise$1 = Promise.resolve();
94372             return _loadViewerPromise$1;
94373           },
94374           showViewer: function showViewer(context) {
94375             var viewer = context.container().select('.photoviewer').classed('hide', false);
94376             var isHidden = viewer.selectAll('.photo-wrapper.osc-wrapper.hide').size();
94377
94378             if (isHidden) {
94379               viewer.selectAll('.photo-wrapper:not(.osc-wrapper)').classed('hide', true);
94380               viewer.selectAll('.photo-wrapper.osc-wrapper').classed('hide', false);
94381             }
94382
94383             return this;
94384           },
94385           hideViewer: function hideViewer(context) {
94386             _oscSelectedImage = null;
94387             this.updateUrlImage(null);
94388             var viewer = context.container().select('.photoviewer');
94389             if (!viewer.empty()) viewer.datum(null);
94390             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
94391             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
94392             return this.setStyles(context, null, true);
94393           },
94394           selectImage: function selectImage(context, imageKey) {
94395             var d = this.cachedImage(imageKey);
94396             _oscSelectedImage = d;
94397             this.updateUrlImage(imageKey);
94398             var viewer = context.container().select('.photoviewer');
94399             if (!viewer.empty()) viewer.datum(d);
94400             this.setStyles(context, null, true);
94401             context.container().selectAll('.icon-sign').classed('currentView', false);
94402             if (!d) return this;
94403             var wrap = context.container().select('.photoviewer .osc-wrapper');
94404             var imageWrap = wrap.selectAll('.osc-image-wrap');
94405             var attribution = wrap.selectAll('.photo-attribution').html('');
94406             wrap.transition().duration(100).call(imgZoom.transform, identity$2);
94407             imageWrap.selectAll('.osc-image').remove();
94408
94409             if (d) {
94410               var sequence = _oscCache.sequences[d.sequence_id];
94411               var r = sequence && sequence.rotation || 0;
94412               imageWrap.append('img').attr('class', 'osc-image').attr('src', apibase$1 + '/' + d.imagePath).style('transform', 'rotate(' + r + 'deg)');
94413
94414               if (d.captured_by) {
94415                 attribution.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://openstreetcam.org/user/' + encodeURIComponent(d.captured_by)).html('@' + d.captured_by);
94416                 attribution.append('span').html('|');
94417               }
94418
94419               if (d.captured_at) {
94420                 attribution.append('span').attr('class', 'captured_at').html(localeDateString(d.captured_at));
94421                 attribution.append('span').html('|');
94422               }
94423
94424               attribution.append('a').attr('class', 'image-link').attr('target', '_blank').attr('href', 'https://openstreetcam.org/details/' + d.sequence_id + '/' + d.sequence_index).html('openstreetcam.org');
94425             }
94426
94427             return this;
94428
94429             function localeDateString(s) {
94430               if (!s) return null;
94431               var options = {
94432                 day: 'numeric',
94433                 month: 'short',
94434                 year: 'numeric'
94435               };
94436               var d = new Date(s);
94437               if (isNaN(d.getTime())) return null;
94438               return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
94439             }
94440           },
94441           getSelectedImage: function getSelectedImage() {
94442             return _oscSelectedImage;
94443           },
94444           getSequenceKeyForImage: function getSequenceKeyForImage(d) {
94445             return d && d.sequence_id;
94446           },
94447           // Updates the currently highlighted sequence and selected bubble.
94448           // Reset is only necessary when interacting with the viewport because
94449           // this implicitly changes the currently selected bubble/sequence
94450           setStyles: function setStyles(context, hovered, reset) {
94451             if (reset) {
94452               // reset all layers
94453               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
94454               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
94455             }
94456
94457             var hoveredImageKey = hovered && hovered.key;
94458             var hoveredSequenceKey = this.getSequenceKeyForImage(hovered);
94459             var hoveredSequence = hoveredSequenceKey && _oscCache.sequences[hoveredSequenceKey];
94460             var hoveredImageKeys = hoveredSequence && hoveredSequence.images.map(function (d) {
94461               return d.key;
94462             }) || [];
94463             var viewer = context.container().select('.photoviewer');
94464             var selected = viewer.empty() ? undefined : viewer.datum();
94465             var selectedImageKey = selected && selected.key;
94466             var selectedSequenceKey = this.getSequenceKeyForImage(selected);
94467             var selectedSequence = selectedSequenceKey && _oscCache.sequences[selectedSequenceKey];
94468             var selectedImageKeys = selectedSequence && selectedSequence.images.map(function (d) {
94469               return d.key;
94470             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
94471
94472             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
94473             context.container().selectAll('.layer-openstreetcam .viewfield-group').classed('highlighted', function (d) {
94474               return highlightedImageKeys.indexOf(d.key) !== -1;
94475             }).classed('hovered', function (d) {
94476               return d.key === hoveredImageKey;
94477             }).classed('currentView', function (d) {
94478               return d.key === selectedImageKey;
94479             });
94480             context.container().selectAll('.layer-openstreetcam .sequence').classed('highlighted', function (d) {
94481               return d.properties.key === hoveredSequenceKey;
94482             }).classed('currentView', function (d) {
94483               return d.properties.key === selectedSequenceKey;
94484             }); // update viewfields if needed
94485
94486             context.container().selectAll('.layer-openstreetcam .viewfield-group .viewfield').attr('d', viewfieldPath);
94487
94488             function viewfieldPath() {
94489               var d = this.parentNode.__data__;
94490
94491               if (d.pano && d.key !== selectedImageKey) {
94492                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
94493               } else {
94494                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
94495               }
94496             }
94497
94498             return this;
94499           },
94500           updateUrlImage: function updateUrlImage(imageKey) {
94501             if (!window.mocha) {
94502               var hash = utilStringQs(window.location.hash);
94503
94504               if (imageKey) {
94505                 hash.photo = 'openstreetcam/' + imageKey;
94506               } else {
94507                 delete hash.photo;
94508               }
94509
94510               window.location.replace('#' + utilQsString(hash, true));
94511             }
94512           },
94513           cache: function cache() {
94514             return _oscCache;
94515           }
94516         };
94517
94518         var hashes = createCommonjsModule(function (module, exports) {
94519           (function () {
94520             var Hashes;
94521
94522             function utf8Encode(str) {
94523               var x,
94524                   y,
94525                   output = '',
94526                   i = -1,
94527                   l;
94528
94529               if (str && str.length) {
94530                 l = str.length;
94531
94532                 while ((i += 1) < l) {
94533                   /* Decode utf-16 surrogate pairs */
94534                   x = str.charCodeAt(i);
94535                   y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
94536
94537                   if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
94538                     x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
94539                     i += 1;
94540                   }
94541                   /* Encode output as utf-8 */
94542
94543
94544                   if (x <= 0x7F) {
94545                     output += String.fromCharCode(x);
94546                   } else if (x <= 0x7FF) {
94547                     output += String.fromCharCode(0xC0 | x >>> 6 & 0x1F, 0x80 | x & 0x3F);
94548                   } else if (x <= 0xFFFF) {
94549                     output += String.fromCharCode(0xE0 | x >>> 12 & 0x0F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
94550                   } else if (x <= 0x1FFFFF) {
94551                     output += String.fromCharCode(0xF0 | x >>> 18 & 0x07, 0x80 | x >>> 12 & 0x3F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
94552                   }
94553                 }
94554               }
94555
94556               return output;
94557             }
94558
94559             function utf8Decode(str) {
94560               var i,
94561                   ac,
94562                   c1,
94563                   c2,
94564                   c3,
94565                   arr = [],
94566                   l;
94567               i = ac = c1 = c2 = c3 = 0;
94568
94569               if (str && str.length) {
94570                 l = str.length;
94571                 str += '';
94572
94573                 while (i < l) {
94574                   c1 = str.charCodeAt(i);
94575                   ac += 1;
94576
94577                   if (c1 < 128) {
94578                     arr[ac] = String.fromCharCode(c1);
94579                     i += 1;
94580                   } else if (c1 > 191 && c1 < 224) {
94581                     c2 = str.charCodeAt(i + 1);
94582                     arr[ac] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
94583                     i += 2;
94584                   } else {
94585                     c2 = str.charCodeAt(i + 1);
94586                     c3 = str.charCodeAt(i + 2);
94587                     arr[ac] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
94588                     i += 3;
94589                   }
94590                 }
94591               }
94592
94593               return arr.join('');
94594             }
94595             /**
94596              * Add integers, wrapping at 2^32. This uses 16-bit operations internally
94597              * to work around bugs in some JS interpreters.
94598              */
94599
94600
94601             function safe_add(x, y) {
94602               var lsw = (x & 0xFFFF) + (y & 0xFFFF),
94603                   msw = (x >> 16) + (y >> 16) + (lsw >> 16);
94604               return msw << 16 | lsw & 0xFFFF;
94605             }
94606             /**
94607              * Bitwise rotate a 32-bit number to the left.
94608              */
94609
94610
94611             function bit_rol(num, cnt) {
94612               return num << cnt | num >>> 32 - cnt;
94613             }
94614             /**
94615              * Convert a raw string to a hex string
94616              */
94617
94618
94619             function rstr2hex(input, hexcase) {
94620               var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
94621                   output = '',
94622                   x,
94623                   i = 0,
94624                   l = input.length;
94625
94626               for (; i < l; i += 1) {
94627                 x = input.charCodeAt(i);
94628                 output += hex_tab.charAt(x >>> 4 & 0x0F) + hex_tab.charAt(x & 0x0F);
94629               }
94630
94631               return output;
94632             }
94633             /**
94634              * Convert an array of big-endian words to a string
94635              */
94636
94637
94638             function binb2rstr(input) {
94639               var i,
94640                   l = input.length * 32,
94641                   output = '';
94642
94643               for (i = 0; i < l; i += 8) {
94644                 output += String.fromCharCode(input[i >> 5] >>> 24 - i % 32 & 0xFF);
94645               }
94646
94647               return output;
94648             }
94649             /**
94650              * Convert an array of little-endian words to a string
94651              */
94652
94653
94654             function binl2rstr(input) {
94655               var i,
94656                   l = input.length * 32,
94657                   output = '';
94658
94659               for (i = 0; i < l; i += 8) {
94660                 output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
94661               }
94662
94663               return output;
94664             }
94665             /**
94666              * Convert a raw string to an array of little-endian words
94667              * Characters >255 have their high-byte silently ignored.
94668              */
94669
94670
94671             function rstr2binl(input) {
94672               var i,
94673                   l = input.length * 8,
94674                   output = Array(input.length >> 2),
94675                   lo = output.length;
94676
94677               for (i = 0; i < lo; i += 1) {
94678                 output[i] = 0;
94679               }
94680
94681               for (i = 0; i < l; i += 8) {
94682                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << i % 32;
94683               }
94684
94685               return output;
94686             }
94687             /**
94688              * Convert a raw string to an array of big-endian words
94689              * Characters >255 have their high-byte silently ignored.
94690              */
94691
94692
94693             function rstr2binb(input) {
94694               var i,
94695                   l = input.length * 8,
94696                   output = Array(input.length >> 2),
94697                   lo = output.length;
94698
94699               for (i = 0; i < lo; i += 1) {
94700                 output[i] = 0;
94701               }
94702
94703               for (i = 0; i < l; i += 8) {
94704                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << 24 - i % 32;
94705               }
94706
94707               return output;
94708             }
94709             /**
94710              * Convert a raw string to an arbitrary string encoding
94711              */
94712
94713
94714             function rstr2any(input, encoding) {
94715               var divisor = encoding.length,
94716                   remainders = Array(),
94717                   i,
94718                   q,
94719                   x,
94720                   ld,
94721                   quotient,
94722                   dividend,
94723                   output,
94724                   full_length;
94725               /* Convert to an array of 16-bit big-endian values, forming the dividend */
94726
94727               dividend = Array(Math.ceil(input.length / 2));
94728               ld = dividend.length;
94729
94730               for (i = 0; i < ld; i += 1) {
94731                 dividend[i] = input.charCodeAt(i * 2) << 8 | input.charCodeAt(i * 2 + 1);
94732               }
94733               /**
94734                * Repeatedly perform a long division. The binary array forms the dividend,
94735                * the length of the encoding is the divisor. Once computed, the quotient
94736                * forms the dividend for the next step. We stop when the dividend is zerHashes.
94737                * All remainders are stored for later use.
94738                */
94739
94740
94741               while (dividend.length > 0) {
94742                 quotient = Array();
94743                 x = 0;
94744
94745                 for (i = 0; i < dividend.length; i += 1) {
94746                   x = (x << 16) + dividend[i];
94747                   q = Math.floor(x / divisor);
94748                   x -= q * divisor;
94749
94750                   if (quotient.length > 0 || q > 0) {
94751                     quotient[quotient.length] = q;
94752                   }
94753                 }
94754
94755                 remainders[remainders.length] = x;
94756                 dividend = quotient;
94757               }
94758               /* Convert the remainders to the output string */
94759
94760
94761               output = '';
94762
94763               for (i = remainders.length - 1; i >= 0; i--) {
94764                 output += encoding.charAt(remainders[i]);
94765               }
94766               /* Append leading zero equivalents */
94767
94768
94769               full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
94770
94771               for (i = output.length; i < full_length; i += 1) {
94772                 output = encoding[0] + output;
94773               }
94774
94775               return output;
94776             }
94777             /**
94778              * Convert a raw string to a base-64 string
94779              */
94780
94781
94782             function rstr2b64(input, b64pad) {
94783               var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
94784                   output = '',
94785                   len = input.length,
94786                   i,
94787                   j,
94788                   triplet;
94789               b64pad = b64pad || '=';
94790
94791               for (i = 0; i < len; i += 3) {
94792                 triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
94793
94794                 for (j = 0; j < 4; j += 1) {
94795                   if (i * 8 + j * 6 > input.length * 8) {
94796                     output += b64pad;
94797                   } else {
94798                     output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
94799                   }
94800                 }
94801               }
94802
94803               return output;
94804             }
94805
94806             Hashes = {
94807               /**
94808                * @property {String} version
94809                * @readonly
94810                */
94811               VERSION: '1.0.6',
94812
94813               /**
94814                * @member Hashes
94815                * @class Base64
94816                * @constructor
94817                */
94818               Base64: function Base64() {
94819                 // private properties
94820                 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
94821                     pad = '=',
94822                     // URL encoding support @todo
94823                 utf8 = true; // by default enable UTF-8 support encoding
94824                 // public method for encoding
94825
94826                 this.encode = function (input) {
94827                   var i,
94828                       j,
94829                       triplet,
94830                       output = '',
94831                       len = input.length;
94832                   pad = pad || '=';
94833                   input = utf8 ? utf8Encode(input) : input;
94834
94835                   for (i = 0; i < len; i += 3) {
94836                     triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
94837
94838                     for (j = 0; j < 4; j += 1) {
94839                       if (i * 8 + j * 6 > len * 8) {
94840                         output += pad;
94841                       } else {
94842                         output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
94843                       }
94844                     }
94845                   }
94846
94847                   return output;
94848                 }; // public method for decoding
94849
94850
94851                 this.decode = function (input) {
94852                   // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
94853                   var i,
94854                       o1,
94855                       o2,
94856                       o3,
94857                       h1,
94858                       h2,
94859                       h3,
94860                       h4,
94861                       bits,
94862                       ac,
94863                       dec = '',
94864                       arr = [];
94865
94866                   if (!input) {
94867                     return input;
94868                   }
94869
94870                   i = ac = 0;
94871                   input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
94872                   //input += '';
94873
94874                   do {
94875                     // unpack four hexets into three octets using index points in b64
94876                     h1 = tab.indexOf(input.charAt(i += 1));
94877                     h2 = tab.indexOf(input.charAt(i += 1));
94878                     h3 = tab.indexOf(input.charAt(i += 1));
94879                     h4 = tab.indexOf(input.charAt(i += 1));
94880                     bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
94881                     o1 = bits >> 16 & 0xff;
94882                     o2 = bits >> 8 & 0xff;
94883                     o3 = bits & 0xff;
94884                     ac += 1;
94885
94886                     if (h3 === 64) {
94887                       arr[ac] = String.fromCharCode(o1);
94888                     } else if (h4 === 64) {
94889                       arr[ac] = String.fromCharCode(o1, o2);
94890                     } else {
94891                       arr[ac] = String.fromCharCode(o1, o2, o3);
94892                     }
94893                   } while (i < input.length);
94894
94895                   dec = arr.join('');
94896                   dec = utf8 ? utf8Decode(dec) : dec;
94897                   return dec;
94898                 }; // set custom pad string
94899
94900
94901                 this.setPad = function (str) {
94902                   pad = str || pad;
94903                   return this;
94904                 }; // set custom tab string characters
94905
94906
94907                 this.setTab = function (str) {
94908                   tab = str || tab;
94909                   return this;
94910                 };
94911
94912                 this.setUTF8 = function (bool) {
94913                   if (typeof bool === 'boolean') {
94914                     utf8 = bool;
94915                   }
94916
94917                   return this;
94918                 };
94919               },
94920
94921               /**
94922                * CRC-32 calculation
94923                * @member Hashes
94924                * @method CRC32
94925                * @static
94926                * @param {String} str Input String
94927                * @return {String}
94928                */
94929               CRC32: function CRC32(str) {
94930                 var crc = 0,
94931                     x = 0,
94932                     y = 0,
94933                     table,
94934                     i,
94935                     iTop;
94936                 str = utf8Encode(str);
94937                 table = ['00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ', '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ', '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ', '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ', 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ', '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ', 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ', '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ', 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ', '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ', 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ', '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ', 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ', '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ', '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ', '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ', '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ', 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ', '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ', 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ', '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ', 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ', '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ', 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ', '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ', 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'].join('');
94938                 crc = crc ^ -1;
94939
94940                 for (i = 0, iTop = str.length; i < iTop; i += 1) {
94941                   y = (crc ^ str.charCodeAt(i)) & 0xFF;
94942                   x = '0x' + table.substr(y * 9, 8);
94943                   crc = crc >>> 8 ^ x;
94944                 } // always return a positive number (that's what >>> 0 does)
94945
94946
94947                 return (crc ^ -1) >>> 0;
94948               },
94949
94950               /**
94951                * @member Hashes
94952                * @class MD5
94953                * @constructor
94954                * @param {Object} [config]
94955                *
94956                * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
94957                * Digest Algorithm, as defined in RFC 1321.
94958                * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
94959                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
94960                * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
94961                */
94962               MD5: function MD5(options) {
94963                 /**
94964                  * Private config properties. You may need to tweak these to be compatible with
94965                  * the server-side, but the defaults work in most cases.
94966                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
94967                  */
94968                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
94969                     // hexadecimal output case format. false - lowercase; true - uppercase
94970                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
94971                     // base-64 pad character. Defaults to '=' for strict RFC compliance
94972                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
94973                 // privileged (public) methods
94974
94975                 this.hex = function (s) {
94976                   return rstr2hex(rstr(s), hexcase);
94977                 };
94978
94979                 this.b64 = function (s) {
94980                   return rstr2b64(rstr(s), b64pad);
94981                 };
94982
94983                 this.any = function (s, e) {
94984                   return rstr2any(rstr(s), e);
94985                 };
94986
94987                 this.raw = function (s) {
94988                   return rstr(s);
94989                 };
94990
94991                 this.hex_hmac = function (k, d) {
94992                   return rstr2hex(rstr_hmac(k, d), hexcase);
94993                 };
94994
94995                 this.b64_hmac = function (k, d) {
94996                   return rstr2b64(rstr_hmac(k, d), b64pad);
94997                 };
94998
94999                 this.any_hmac = function (k, d, e) {
95000                   return rstr2any(rstr_hmac(k, d), e);
95001                 };
95002                 /**
95003                  * Perform a simple self-test to see if the VM is working
95004                  * @return {String} Hexadecimal hash sample
95005                  */
95006
95007
95008                 this.vm_test = function () {
95009                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
95010                 };
95011                 /**
95012                  * Enable/disable uppercase hexadecimal returned string
95013                  * @param {Boolean}
95014                  * @return {Object} this
95015                  */
95016
95017
95018                 this.setUpperCase = function (a) {
95019                   if (typeof a === 'boolean') {
95020                     hexcase = a;
95021                   }
95022
95023                   return this;
95024                 };
95025                 /**
95026                  * Defines a base64 pad string
95027                  * @param {String} Pad
95028                  * @return {Object} this
95029                  */
95030
95031
95032                 this.setPad = function (a) {
95033                   b64pad = a || b64pad;
95034                   return this;
95035                 };
95036                 /**
95037                  * Defines a base64 pad string
95038                  * @param {Boolean}
95039                  * @return {Object} [this]
95040                  */
95041
95042
95043                 this.setUTF8 = function (a) {
95044                   if (typeof a === 'boolean') {
95045                     utf8 = a;
95046                   }
95047
95048                   return this;
95049                 }; // private methods
95050
95051                 /**
95052                  * Calculate the MD5 of a raw string
95053                  */
95054
95055
95056                 function rstr(s) {
95057                   s = utf8 ? utf8Encode(s) : s;
95058                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
95059                 }
95060                 /**
95061                  * Calculate the HMAC-MD5, of a key and some data (raw strings)
95062                  */
95063
95064
95065                 function rstr_hmac(key, data) {
95066                   var bkey, ipad, opad, hash, i;
95067                   key = utf8 ? utf8Encode(key) : key;
95068                   data = utf8 ? utf8Encode(data) : data;
95069                   bkey = rstr2binl(key);
95070
95071                   if (bkey.length > 16) {
95072                     bkey = binl(bkey, key.length * 8);
95073                   }
95074
95075                   ipad = Array(16), opad = Array(16);
95076
95077                   for (i = 0; i < 16; i += 1) {
95078                     ipad[i] = bkey[i] ^ 0x36363636;
95079                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
95080                   }
95081
95082                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
95083                   return binl2rstr(binl(opad.concat(hash), 512 + 128));
95084                 }
95085                 /**
95086                  * Calculate the MD5 of an array of little-endian words, and a bit length.
95087                  */
95088
95089
95090                 function binl(x, len) {
95091                   var i,
95092                       olda,
95093                       oldb,
95094                       oldc,
95095                       oldd,
95096                       a = 1732584193,
95097                       b = -271733879,
95098                       c = -1732584194,
95099                       d = 271733878;
95100                   /* append padding */
95101
95102                   x[len >> 5] |= 0x80 << len % 32;
95103                   x[(len + 64 >>> 9 << 4) + 14] = len;
95104
95105                   for (i = 0; i < x.length; i += 16) {
95106                     olda = a;
95107                     oldb = b;
95108                     oldc = c;
95109                     oldd = d;
95110                     a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
95111                     d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
95112                     c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
95113                     b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
95114                     a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
95115                     d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
95116                     c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
95117                     b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
95118                     a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
95119                     d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
95120                     c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
95121                     b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
95122                     a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
95123                     d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
95124                     c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
95125                     b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
95126                     a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
95127                     d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
95128                     c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
95129                     b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
95130                     a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
95131                     d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
95132                     c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
95133                     b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
95134                     a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
95135                     d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
95136                     c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
95137                     b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
95138                     a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
95139                     d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
95140                     c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
95141                     b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
95142                     a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
95143                     d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
95144                     c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
95145                     b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
95146                     a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
95147                     d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
95148                     c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
95149                     b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
95150                     a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
95151                     d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
95152                     c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
95153                     b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
95154                     a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
95155                     d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
95156                     c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
95157                     b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
95158                     a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
95159                     d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
95160                     c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
95161                     b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
95162                     a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
95163                     d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
95164                     c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
95165                     b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
95166                     a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
95167                     d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
95168                     c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
95169                     b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
95170                     a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
95171                     d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
95172                     c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
95173                     b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
95174                     a = safe_add(a, olda);
95175                     b = safe_add(b, oldb);
95176                     c = safe_add(c, oldc);
95177                     d = safe_add(d, oldd);
95178                   }
95179
95180                   return Array(a, b, c, d);
95181                 }
95182                 /**
95183                  * These functions implement the four basic operations the algorithm uses.
95184                  */
95185
95186
95187                 function md5_cmn(q, a, b, x, s, t) {
95188                   return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
95189                 }
95190
95191                 function md5_ff(a, b, c, d, x, s, t) {
95192                   return md5_cmn(b & c | ~b & d, a, b, x, s, t);
95193                 }
95194
95195                 function md5_gg(a, b, c, d, x, s, t) {
95196                   return md5_cmn(b & d | c & ~d, a, b, x, s, t);
95197                 }
95198
95199                 function md5_hh(a, b, c, d, x, s, t) {
95200                   return md5_cmn(b ^ c ^ d, a, b, x, s, t);
95201                 }
95202
95203                 function md5_ii(a, b, c, d, x, s, t) {
95204                   return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
95205                 }
95206               },
95207
95208               /**
95209                * @member Hashes
95210                * @class Hashes.SHA1
95211                * @param {Object} [config]
95212                * @constructor
95213                *
95214                * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
95215                * Version 2.2 Copyright Paul Johnston 2000 - 2009.
95216                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
95217                * See http://pajhome.org.uk/crypt/md5 for details.
95218                */
95219               SHA1: function SHA1(options) {
95220                 /**
95221                  * Private config properties. You may need to tweak these to be compatible with
95222                  * the server-side, but the defaults work in most cases.
95223                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
95224                  */
95225                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
95226                     // hexadecimal output case format. false - lowercase; true - uppercase
95227                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
95228                     // base-64 pad character. Defaults to '=' for strict RFC compliance
95229                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
95230                 // public methods
95231
95232                 this.hex = function (s) {
95233                   return rstr2hex(rstr(s), hexcase);
95234                 };
95235
95236                 this.b64 = function (s) {
95237                   return rstr2b64(rstr(s), b64pad);
95238                 };
95239
95240                 this.any = function (s, e) {
95241                   return rstr2any(rstr(s), e);
95242                 };
95243
95244                 this.raw = function (s) {
95245                   return rstr(s);
95246                 };
95247
95248                 this.hex_hmac = function (k, d) {
95249                   return rstr2hex(rstr_hmac(k, d));
95250                 };
95251
95252                 this.b64_hmac = function (k, d) {
95253                   return rstr2b64(rstr_hmac(k, d), b64pad);
95254                 };
95255
95256                 this.any_hmac = function (k, d, e) {
95257                   return rstr2any(rstr_hmac(k, d), e);
95258                 };
95259                 /**
95260                  * Perform a simple self-test to see if the VM is working
95261                  * @return {String} Hexadecimal hash sample
95262                  * @public
95263                  */
95264
95265
95266                 this.vm_test = function () {
95267                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
95268                 };
95269                 /**
95270                  * @description Enable/disable uppercase hexadecimal returned string
95271                  * @param {boolean}
95272                  * @return {Object} this
95273                  * @public
95274                  */
95275
95276
95277                 this.setUpperCase = function (a) {
95278                   if (typeof a === 'boolean') {
95279                     hexcase = a;
95280                   }
95281
95282                   return this;
95283                 };
95284                 /**
95285                  * @description Defines a base64 pad string
95286                  * @param {string} Pad
95287                  * @return {Object} this
95288                  * @public
95289                  */
95290
95291
95292                 this.setPad = function (a) {
95293                   b64pad = a || b64pad;
95294                   return this;
95295                 };
95296                 /**
95297                  * @description Defines a base64 pad string
95298                  * @param {boolean}
95299                  * @return {Object} this
95300                  * @public
95301                  */
95302
95303
95304                 this.setUTF8 = function (a) {
95305                   if (typeof a === 'boolean') {
95306                     utf8 = a;
95307                   }
95308
95309                   return this;
95310                 }; // private methods
95311
95312                 /**
95313                  * Calculate the SHA-512 of a raw string
95314                  */
95315
95316
95317                 function rstr(s) {
95318                   s = utf8 ? utf8Encode(s) : s;
95319                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
95320                 }
95321                 /**
95322                  * Calculate the HMAC-SHA1 of a key and some data (raw strings)
95323                  */
95324
95325
95326                 function rstr_hmac(key, data) {
95327                   var bkey, ipad, opad, i, hash;
95328                   key = utf8 ? utf8Encode(key) : key;
95329                   data = utf8 ? utf8Encode(data) : data;
95330                   bkey = rstr2binb(key);
95331
95332                   if (bkey.length > 16) {
95333                     bkey = binb(bkey, key.length * 8);
95334                   }
95335
95336                   ipad = Array(16), opad = Array(16);
95337
95338                   for (i = 0; i < 16; i += 1) {
95339                     ipad[i] = bkey[i] ^ 0x36363636;
95340                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
95341                   }
95342
95343                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
95344                   return binb2rstr(binb(opad.concat(hash), 512 + 160));
95345                 }
95346                 /**
95347                  * Calculate the SHA-1 of an array of big-endian words, and a bit length
95348                  */
95349
95350
95351                 function binb(x, len) {
95352                   var i,
95353                       j,
95354                       t,
95355                       olda,
95356                       oldb,
95357                       oldc,
95358                       oldd,
95359                       olde,
95360                       w = Array(80),
95361                       a = 1732584193,
95362                       b = -271733879,
95363                       c = -1732584194,
95364                       d = 271733878,
95365                       e = -1009589776;
95366                   /* append padding */
95367
95368                   x[len >> 5] |= 0x80 << 24 - len % 32;
95369                   x[(len + 64 >> 9 << 4) + 15] = len;
95370
95371                   for (i = 0; i < x.length; i += 16) {
95372                     olda = a;
95373                     oldb = b;
95374                     oldc = c;
95375                     oldd = d;
95376                     olde = e;
95377
95378                     for (j = 0; j < 80; j += 1) {
95379                       if (j < 16) {
95380                         w[j] = x[i + j];
95381                       } else {
95382                         w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
95383                       }
95384
95385                       t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));
95386                       e = d;
95387                       d = c;
95388                       c = bit_rol(b, 30);
95389                       b = a;
95390                       a = t;
95391                     }
95392
95393                     a = safe_add(a, olda);
95394                     b = safe_add(b, oldb);
95395                     c = safe_add(c, oldc);
95396                     d = safe_add(d, oldd);
95397                     e = safe_add(e, olde);
95398                   }
95399
95400                   return Array(a, b, c, d, e);
95401                 }
95402                 /**
95403                  * Perform the appropriate triplet combination function for the current
95404                  * iteration
95405                  */
95406
95407
95408                 function sha1_ft(t, b, c, d) {
95409                   if (t < 20) {
95410                     return b & c | ~b & d;
95411                   }
95412
95413                   if (t < 40) {
95414                     return b ^ c ^ d;
95415                   }
95416
95417                   if (t < 60) {
95418                     return b & c | b & d | c & d;
95419                   }
95420
95421                   return b ^ c ^ d;
95422                 }
95423                 /**
95424                  * Determine the appropriate additive constant for the current iteration
95425                  */
95426
95427
95428                 function sha1_kt(t) {
95429                   return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514;
95430                 }
95431               },
95432
95433               /**
95434                * @class Hashes.SHA256
95435                * @param {config}
95436                *
95437                * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
95438                * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
95439                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
95440                * See http://pajhome.org.uk/crypt/md5 for details.
95441                * Also http://anmar.eu.org/projects/jssha2/
95442                */
95443               SHA256: function SHA256(options) {
95444                 /**
95445                  * Private properties configuration variables. You may need to tweak these to be compatible with
95446                  * the server-side, but the defaults work in most cases.
95447                  * @see this.setUpperCase() method
95448                  * @see this.setPad() method
95449                  */
95450                 options && typeof options.uppercase === 'boolean' ? options.uppercase : false;
95451                     var // hexadecimal output case format. false - lowercase; true - uppercase  */
95452                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
95453
95454                 /* base-64 pad character. Default '=' for strict RFC compliance   */
95455                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
95456
95457                 /* enable/disable utf8 encoding */
95458                 sha256_K;
95459                 /* privileged (public) methods */
95460
95461                 this.hex = function (s) {
95462                   return rstr2hex(rstr(s, utf8));
95463                 };
95464
95465                 this.b64 = function (s) {
95466                   return rstr2b64(rstr(s, utf8), b64pad);
95467                 };
95468
95469                 this.any = function (s, e) {
95470                   return rstr2any(rstr(s, utf8), e);
95471                 };
95472
95473                 this.raw = function (s) {
95474                   return rstr(s, utf8);
95475                 };
95476
95477                 this.hex_hmac = function (k, d) {
95478                   return rstr2hex(rstr_hmac(k, d));
95479                 };
95480
95481                 this.b64_hmac = function (k, d) {
95482                   return rstr2b64(rstr_hmac(k, d), b64pad);
95483                 };
95484
95485                 this.any_hmac = function (k, d, e) {
95486                   return rstr2any(rstr_hmac(k, d), e);
95487                 };
95488                 /**
95489                  * Perform a simple self-test to see if the VM is working
95490                  * @return {String} Hexadecimal hash sample
95491                  * @public
95492                  */
95493
95494
95495                 this.vm_test = function () {
95496                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
95497                 };
95498                 /**
95499                  * Enable/disable uppercase hexadecimal returned string
95500                  * @param {boolean}
95501                  * @return {Object} this
95502                  * @public
95503                  */
95504
95505
95506                 this.setUpperCase = function (a) {
95507
95508                   return this;
95509                 };
95510                 /**
95511                  * @description Defines a base64 pad string
95512                  * @param {string} Pad
95513                  * @return {Object} this
95514                  * @public
95515                  */
95516
95517
95518                 this.setPad = function (a) {
95519                   b64pad = a || b64pad;
95520                   return this;
95521                 };
95522                 /**
95523                  * Defines a base64 pad string
95524                  * @param {boolean}
95525                  * @return {Object} this
95526                  * @public
95527                  */
95528
95529
95530                 this.setUTF8 = function (a) {
95531                   if (typeof a === 'boolean') {
95532                     utf8 = a;
95533                   }
95534
95535                   return this;
95536                 }; // private methods
95537
95538                 /**
95539                  * Calculate the SHA-512 of a raw string
95540                  */
95541
95542
95543                 function rstr(s, utf8) {
95544                   s = utf8 ? utf8Encode(s) : s;
95545                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
95546                 }
95547                 /**
95548                  * Calculate the HMAC-sha256 of a key and some data (raw strings)
95549                  */
95550
95551
95552                 function rstr_hmac(key, data) {
95553                   key = utf8 ? utf8Encode(key) : key;
95554                   data = utf8 ? utf8Encode(data) : data;
95555                   var hash,
95556                       i = 0,
95557                       bkey = rstr2binb(key),
95558                       ipad = Array(16),
95559                       opad = Array(16);
95560
95561                   if (bkey.length > 16) {
95562                     bkey = binb(bkey, key.length * 8);
95563                   }
95564
95565                   for (; i < 16; i += 1) {
95566                     ipad[i] = bkey[i] ^ 0x36363636;
95567                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
95568                   }
95569
95570                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
95571                   return binb2rstr(binb(opad.concat(hash), 512 + 256));
95572                 }
95573                 /*
95574                  * Main sha256 function, with its support functions
95575                  */
95576
95577
95578                 function sha256_S(X, n) {
95579                   return X >>> n | X << 32 - n;
95580                 }
95581
95582                 function sha256_R(X, n) {
95583                   return X >>> n;
95584                 }
95585
95586                 function sha256_Ch(x, y, z) {
95587                   return x & y ^ ~x & z;
95588                 }
95589
95590                 function sha256_Maj(x, y, z) {
95591                   return x & y ^ x & z ^ y & z;
95592                 }
95593
95594                 function sha256_Sigma0256(x) {
95595                   return sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22);
95596                 }
95597
95598                 function sha256_Sigma1256(x) {
95599                   return sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25);
95600                 }
95601
95602                 function sha256_Gamma0256(x) {
95603                   return sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3);
95604                 }
95605
95606                 function sha256_Gamma1256(x) {
95607                   return sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10);
95608                 }
95609
95610                 sha256_K = [1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987, 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998];
95611
95612                 function binb(m, l) {
95613                   var HASH = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225];
95614                   var W = new Array(64);
95615                   var a, b, c, d, e, f, g, h;
95616                   var i, j, T1, T2;
95617                   /* append padding */
95618
95619                   m[l >> 5] |= 0x80 << 24 - l % 32;
95620                   m[(l + 64 >> 9 << 4) + 15] = l;
95621
95622                   for (i = 0; i < m.length; i += 16) {
95623                     a = HASH[0];
95624                     b = HASH[1];
95625                     c = HASH[2];
95626                     d = HASH[3];
95627                     e = HASH[4];
95628                     f = HASH[5];
95629                     g = HASH[6];
95630                     h = HASH[7];
95631
95632                     for (j = 0; j < 64; j += 1) {
95633                       if (j < 16) {
95634                         W[j] = m[j + i];
95635                       } else {
95636                         W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), sha256_Gamma0256(W[j - 15])), W[j - 16]);
95637                       }
95638
95639                       T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), sha256_K[j]), W[j]);
95640                       T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
95641                       h = g;
95642                       g = f;
95643                       f = e;
95644                       e = safe_add(d, T1);
95645                       d = c;
95646                       c = b;
95647                       b = a;
95648                       a = safe_add(T1, T2);
95649                     }
95650
95651                     HASH[0] = safe_add(a, HASH[0]);
95652                     HASH[1] = safe_add(b, HASH[1]);
95653                     HASH[2] = safe_add(c, HASH[2]);
95654                     HASH[3] = safe_add(d, HASH[3]);
95655                     HASH[4] = safe_add(e, HASH[4]);
95656                     HASH[5] = safe_add(f, HASH[5]);
95657                     HASH[6] = safe_add(g, HASH[6]);
95658                     HASH[7] = safe_add(h, HASH[7]);
95659                   }
95660
95661                   return HASH;
95662                 }
95663               },
95664
95665               /**
95666                * @class Hashes.SHA512
95667                * @param {config}
95668                *
95669                * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
95670                * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
95671                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
95672                * See http://pajhome.org.uk/crypt/md5 for details.
95673                */
95674               SHA512: function SHA512(options) {
95675                 /**
95676                  * Private properties configuration variables. You may need to tweak these to be compatible with
95677                  * the server-side, but the defaults work in most cases.
95678                  * @see this.setUpperCase() method
95679                  * @see this.setPad() method
95680                  */
95681                 options && typeof options.uppercase === 'boolean' ? options.uppercase : false;
95682
95683                 var /* hexadecimal output case format. false - lowercase; true - uppercase  */
95684                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
95685
95686                 /* base-64 pad character. Default '=' for strict RFC compliance   */
95687                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
95688
95689                 /* enable/disable utf8 encoding */
95690                 sha512_k;
95691                 /* privileged (public) methods */
95692
95693                 this.hex = function (s) {
95694                   return rstr2hex(rstr(s));
95695                 };
95696
95697                 this.b64 = function (s) {
95698                   return rstr2b64(rstr(s), b64pad);
95699                 };
95700
95701                 this.any = function (s, e) {
95702                   return rstr2any(rstr(s), e);
95703                 };
95704
95705                 this.raw = function (s) {
95706                   return rstr(s);
95707                 };
95708
95709                 this.hex_hmac = function (k, d) {
95710                   return rstr2hex(rstr_hmac(k, d));
95711                 };
95712
95713                 this.b64_hmac = function (k, d) {
95714                   return rstr2b64(rstr_hmac(k, d), b64pad);
95715                 };
95716
95717                 this.any_hmac = function (k, d, e) {
95718                   return rstr2any(rstr_hmac(k, d), e);
95719                 };
95720                 /**
95721                  * Perform a simple self-test to see if the VM is working
95722                  * @return {String} Hexadecimal hash sample
95723                  * @public
95724                  */
95725
95726
95727                 this.vm_test = function () {
95728                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
95729                 };
95730                 /**
95731                  * @description Enable/disable uppercase hexadecimal returned string
95732                  * @param {boolean}
95733                  * @return {Object} this
95734                  * @public
95735                  */
95736
95737
95738                 this.setUpperCase = function (a) {
95739
95740                   return this;
95741                 };
95742                 /**
95743                  * @description Defines a base64 pad string
95744                  * @param {string} Pad
95745                  * @return {Object} this
95746                  * @public
95747                  */
95748
95749
95750                 this.setPad = function (a) {
95751                   b64pad = a || b64pad;
95752                   return this;
95753                 };
95754                 /**
95755                  * @description Defines a base64 pad string
95756                  * @param {boolean}
95757                  * @return {Object} this
95758                  * @public
95759                  */
95760
95761
95762                 this.setUTF8 = function (a) {
95763                   if (typeof a === 'boolean') {
95764                     utf8 = a;
95765                   }
95766
95767                   return this;
95768                 };
95769                 /* private methods */
95770
95771                 /**
95772                  * Calculate the SHA-512 of a raw string
95773                  */
95774
95775
95776                 function rstr(s) {
95777                   s = utf8 ? utf8Encode(s) : s;
95778                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
95779                 }
95780                 /*
95781                  * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
95782                  */
95783
95784
95785                 function rstr_hmac(key, data) {
95786                   key = utf8 ? utf8Encode(key) : key;
95787                   data = utf8 ? utf8Encode(data) : data;
95788                   var hash,
95789                       i = 0,
95790                       bkey = rstr2binb(key),
95791                       ipad = Array(32),
95792                       opad = Array(32);
95793
95794                   if (bkey.length > 32) {
95795                     bkey = binb(bkey, key.length * 8);
95796                   }
95797
95798                   for (; i < 32; i += 1) {
95799                     ipad[i] = bkey[i] ^ 0x36363636;
95800                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
95801                   }
95802
95803                   hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
95804                   return binb2rstr(binb(opad.concat(hash), 1024 + 512));
95805                 }
95806                 /**
95807                  * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
95808                  */
95809
95810
95811                 function binb(x, len) {
95812                   var j,
95813                       i,
95814                       l,
95815                       W = new Array(80),
95816                       hash = new Array(16),
95817                       //Initial hash values
95818                   H = [new int64(0x6a09e667, -205731576), new int64(-1150833019, -2067093701), new int64(0x3c6ef372, -23791573), new int64(-1521486534, 0x5f1d36f1), new int64(0x510e527f, -1377402159), new int64(-1694144372, 0x2b3e6c1f), new int64(0x1f83d9ab, -79577749), new int64(0x5be0cd19, 0x137e2179)],
95819                       T1 = new int64(0, 0),
95820                       T2 = new int64(0, 0),
95821                       a = new int64(0, 0),
95822                       b = new int64(0, 0),
95823                       c = new int64(0, 0),
95824                       d = new int64(0, 0),
95825                       e = new int64(0, 0),
95826                       f = new int64(0, 0),
95827                       g = new int64(0, 0),
95828                       h = new int64(0, 0),
95829                       //Temporary variables not specified by the document
95830                   s0 = new int64(0, 0),
95831                       s1 = new int64(0, 0),
95832                       Ch = new int64(0, 0),
95833                       Maj = new int64(0, 0),
95834                       r1 = new int64(0, 0),
95835                       r2 = new int64(0, 0),
95836                       r3 = new int64(0, 0);
95837
95838                   if (sha512_k === undefined) {
95839                     //SHA512 constants
95840                     sha512_k = [new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd), new int64(-1245643825, -330482897), new int64(-373957723, -2121671748), new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031), new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736), new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe), new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302), new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1), new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428), new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3), new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65), new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483), new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459), new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210), new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340), new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395), new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70), new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926), new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473), new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8), new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b), new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023), new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30), new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910), new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8), new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53), new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016), new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893), new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397), new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60), new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec), new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047), new int64(-1090935817, -1295615723), new int64(-965641998, -479046869), new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207), new int64(-354779690, -840897762), new int64(-176337025, -294727304), new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026), new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b), new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493), new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620), new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430), new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)];
95841                   }
95842
95843                   for (i = 0; i < 80; i += 1) {
95844                     W[i] = new int64(0, 0);
95845                   } // append padding to the source string. The format is described in the FIPS.
95846
95847
95848                   x[len >> 5] |= 0x80 << 24 - (len & 0x1f);
95849                   x[(len + 128 >> 10 << 5) + 31] = len;
95850                   l = x.length;
95851
95852                   for (i = 0; i < l; i += 32) {
95853                     //32 dwords is the block size
95854                     int64copy(a, H[0]);
95855                     int64copy(b, H[1]);
95856                     int64copy(c, H[2]);
95857                     int64copy(d, H[3]);
95858                     int64copy(e, H[4]);
95859                     int64copy(f, H[5]);
95860                     int64copy(g, H[6]);
95861                     int64copy(h, H[7]);
95862
95863                     for (j = 0; j < 16; j += 1) {
95864                       W[j].h = x[i + 2 * j];
95865                       W[j].l = x[i + 2 * j + 1];
95866                     }
95867
95868                     for (j = 16; j < 80; j += 1) {
95869                       //sigma1
95870                       int64rrot(r1, W[j - 2], 19);
95871                       int64revrrot(r2, W[j - 2], 29);
95872                       int64shr(r3, W[j - 2], 6);
95873                       s1.l = r1.l ^ r2.l ^ r3.l;
95874                       s1.h = r1.h ^ r2.h ^ r3.h; //sigma0
95875
95876                       int64rrot(r1, W[j - 15], 1);
95877                       int64rrot(r2, W[j - 15], 8);
95878                       int64shr(r3, W[j - 15], 7);
95879                       s0.l = r1.l ^ r2.l ^ r3.l;
95880                       s0.h = r1.h ^ r2.h ^ r3.h;
95881                       int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
95882                     }
95883
95884                     for (j = 0; j < 80; j += 1) {
95885                       //Ch
95886                       Ch.l = e.l & f.l ^ ~e.l & g.l;
95887                       Ch.h = e.h & f.h ^ ~e.h & g.h; //Sigma1
95888
95889                       int64rrot(r1, e, 14);
95890                       int64rrot(r2, e, 18);
95891                       int64revrrot(r3, e, 9);
95892                       s1.l = r1.l ^ r2.l ^ r3.l;
95893                       s1.h = r1.h ^ r2.h ^ r3.h; //Sigma0
95894
95895                       int64rrot(r1, a, 28);
95896                       int64revrrot(r2, a, 2);
95897                       int64revrrot(r3, a, 7);
95898                       s0.l = r1.l ^ r2.l ^ r3.l;
95899                       s0.h = r1.h ^ r2.h ^ r3.h; //Maj
95900
95901                       Maj.l = a.l & b.l ^ a.l & c.l ^ b.l & c.l;
95902                       Maj.h = a.h & b.h ^ a.h & c.h ^ b.h & c.h;
95903                       int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
95904                       int64add(T2, s0, Maj);
95905                       int64copy(h, g);
95906                       int64copy(g, f);
95907                       int64copy(f, e);
95908                       int64add(e, d, T1);
95909                       int64copy(d, c);
95910                       int64copy(c, b);
95911                       int64copy(b, a);
95912                       int64add(a, T1, T2);
95913                     }
95914
95915                     int64add(H[0], H[0], a);
95916                     int64add(H[1], H[1], b);
95917                     int64add(H[2], H[2], c);
95918                     int64add(H[3], H[3], d);
95919                     int64add(H[4], H[4], e);
95920                     int64add(H[5], H[5], f);
95921                     int64add(H[6], H[6], g);
95922                     int64add(H[7], H[7], h);
95923                   } //represent the hash as an array of 32-bit dwords
95924
95925
95926                   for (i = 0; i < 8; i += 1) {
95927                     hash[2 * i] = H[i].h;
95928                     hash[2 * i + 1] = H[i].l;
95929                   }
95930
95931                   return hash;
95932                 } //A constructor for 64-bit numbers
95933
95934
95935                 function int64(h, l) {
95936                   this.h = h;
95937                   this.l = l; //this.toString = int64toString;
95938                 } //Copies src into dst, assuming both are 64-bit numbers
95939
95940
95941                 function int64copy(dst, src) {
95942                   dst.h = src.h;
95943                   dst.l = src.l;
95944                 } //Right-rotates a 64-bit number by shift
95945                 //Won't handle cases of shift>=32
95946                 //The function revrrot() is for that
95947
95948
95949                 function int64rrot(dst, x, shift) {
95950                   dst.l = x.l >>> shift | x.h << 32 - shift;
95951                   dst.h = x.h >>> shift | x.l << 32 - shift;
95952                 } //Reverses the dwords of the source and then rotates right by shift.
95953                 //This is equivalent to rotation by 32+shift
95954
95955
95956                 function int64revrrot(dst, x, shift) {
95957                   dst.l = x.h >>> shift | x.l << 32 - shift;
95958                   dst.h = x.l >>> shift | x.h << 32 - shift;
95959                 } //Bitwise-shifts right a 64-bit number by shift
95960                 //Won't handle shift>=32, but it's never needed in SHA512
95961
95962
95963                 function int64shr(dst, x, shift) {
95964                   dst.l = x.l >>> shift | x.h << 32 - shift;
95965                   dst.h = x.h >>> shift;
95966                 } //Adds two 64-bit numbers
95967                 //Like the original implementation, does not rely on 32-bit operations
95968
95969
95970                 function int64add(dst, x, y) {
95971                   var w0 = (x.l & 0xffff) + (y.l & 0xffff);
95972                   var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
95973                   var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
95974                   var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
95975                   dst.l = w0 & 0xffff | w1 << 16;
95976                   dst.h = w2 & 0xffff | w3 << 16;
95977                 } //Same, except with 4 addends. Works faster than adding them one by one.
95978
95979
95980                 function int64add4(dst, a, b, c, d) {
95981                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
95982                   var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
95983                   var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
95984                   var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
95985                   dst.l = w0 & 0xffff | w1 << 16;
95986                   dst.h = w2 & 0xffff | w3 << 16;
95987                 } //Same, except with 5 addends
95988
95989
95990                 function int64add5(dst, a, b, c, d, e) {
95991                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
95992                       w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
95993                       w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
95994                       w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
95995                   dst.l = w0 & 0xffff | w1 << 16;
95996                   dst.h = w2 & 0xffff | w3 << 16;
95997                 }
95998               },
95999
96000               /**
96001                * @class Hashes.RMD160
96002                * @constructor
96003                * @param {Object} [config]
96004                *
96005                * A JavaScript implementation of the RIPEMD-160 Algorithm
96006                * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
96007                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
96008                * See http://pajhome.org.uk/crypt/md5 for details.
96009                * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
96010                */
96011               RMD160: function RMD160(options) {
96012                 /**
96013                  * Private properties configuration variables. You may need to tweak these to be compatible with
96014                  * the server-side, but the defaults work in most cases.
96015                  * @see this.setUpperCase() method
96016                  * @see this.setPad() method
96017                  */
96018                 options && typeof options.uppercase === 'boolean' ? options.uppercase : false;
96019
96020                 var /* hexadecimal output case format. false - lowercase; true - uppercase  */
96021                 b64pad = options && typeof options.pad === 'string' ? options.pa : '=',
96022
96023                 /* base-64 pad character. Default '=' for strict RFC compliance   */
96024                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
96025
96026                 /* enable/disable utf8 encoding */
96027                 rmd160_r1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13],
96028                     rmd160_r2 = [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11],
96029                     rmd160_s1 = [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6],
96030                     rmd160_s2 = [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11];
96031                 /* privileged (public) methods */
96032
96033                 this.hex = function (s) {
96034                   return rstr2hex(rstr(s));
96035                 };
96036
96037                 this.b64 = function (s) {
96038                   return rstr2b64(rstr(s), b64pad);
96039                 };
96040
96041                 this.any = function (s, e) {
96042                   return rstr2any(rstr(s), e);
96043                 };
96044
96045                 this.raw = function (s) {
96046                   return rstr(s);
96047                 };
96048
96049                 this.hex_hmac = function (k, d) {
96050                   return rstr2hex(rstr_hmac(k, d));
96051                 };
96052
96053                 this.b64_hmac = function (k, d) {
96054                   return rstr2b64(rstr_hmac(k, d), b64pad);
96055                 };
96056
96057                 this.any_hmac = function (k, d, e) {
96058                   return rstr2any(rstr_hmac(k, d), e);
96059                 };
96060                 /**
96061                  * Perform a simple self-test to see if the VM is working
96062                  * @return {String} Hexadecimal hash sample
96063                  * @public
96064                  */
96065
96066
96067                 this.vm_test = function () {
96068                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
96069                 };
96070                 /**
96071                  * @description Enable/disable uppercase hexadecimal returned string
96072                  * @param {boolean}
96073                  * @return {Object} this
96074                  * @public
96075                  */
96076
96077
96078                 this.setUpperCase = function (a) {
96079
96080                   return this;
96081                 };
96082                 /**
96083                  * @description Defines a base64 pad string
96084                  * @param {string} Pad
96085                  * @return {Object} this
96086                  * @public
96087                  */
96088
96089
96090                 this.setPad = function (a) {
96091                   if (typeof a !== 'undefined') {
96092                     b64pad = a;
96093                   }
96094
96095                   return this;
96096                 };
96097                 /**
96098                  * @description Defines a base64 pad string
96099                  * @param {boolean}
96100                  * @return {Object} this
96101                  * @public
96102                  */
96103
96104
96105                 this.setUTF8 = function (a) {
96106                   if (typeof a === 'boolean') {
96107                     utf8 = a;
96108                   }
96109
96110                   return this;
96111                 };
96112                 /* private methods */
96113
96114                 /**
96115                  * Calculate the rmd160 of a raw string
96116                  */
96117
96118
96119                 function rstr(s) {
96120                   s = utf8 ? utf8Encode(s) : s;
96121                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
96122                 }
96123                 /**
96124                  * Calculate the HMAC-rmd160 of a key and some data (raw strings)
96125                  */
96126
96127
96128                 function rstr_hmac(key, data) {
96129                   key = utf8 ? utf8Encode(key) : key;
96130                   data = utf8 ? utf8Encode(data) : data;
96131                   var i,
96132                       hash,
96133                       bkey = rstr2binl(key),
96134                       ipad = Array(16),
96135                       opad = Array(16);
96136
96137                   if (bkey.length > 16) {
96138                     bkey = binl(bkey, key.length * 8);
96139                   }
96140
96141                   for (i = 0; i < 16; i += 1) {
96142                     ipad[i] = bkey[i] ^ 0x36363636;
96143                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
96144                   }
96145
96146                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
96147                   return binl2rstr(binl(opad.concat(hash), 512 + 160));
96148                 }
96149                 /**
96150                  * Convert an array of little-endian words to a string
96151                  */
96152
96153
96154                 function binl2rstr(input) {
96155                   var i,
96156                       output = '',
96157                       l = input.length * 32;
96158
96159                   for (i = 0; i < l; i += 8) {
96160                     output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
96161                   }
96162
96163                   return output;
96164                 }
96165                 /**
96166                  * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
96167                  */
96168
96169
96170                 function binl(x, len) {
96171                   var T,
96172                       j,
96173                       i,
96174                       l,
96175                       h0 = 0x67452301,
96176                       h1 = 0xefcdab89,
96177                       h2 = 0x98badcfe,
96178                       h3 = 0x10325476,
96179                       h4 = 0xc3d2e1f0,
96180                       A1,
96181                       B1,
96182                       C1,
96183                       D1,
96184                       E1,
96185                       A2,
96186                       B2,
96187                       C2,
96188                       D2,
96189                       E2;
96190                   /* append padding */
96191
96192                   x[len >> 5] |= 0x80 << len % 32;
96193                   x[(len + 64 >>> 9 << 4) + 14] = len;
96194                   l = x.length;
96195
96196                   for (i = 0; i < l; i += 16) {
96197                     A1 = A2 = h0;
96198                     B1 = B2 = h1;
96199                     C1 = C2 = h2;
96200                     D1 = D2 = h3;
96201                     E1 = E2 = h4;
96202
96203                     for (j = 0; j <= 79; j += 1) {
96204                       T = safe_add(A1, rmd160_f(j, B1, C1, D1));
96205                       T = safe_add(T, x[i + rmd160_r1[j]]);
96206                       T = safe_add(T, rmd160_K1(j));
96207                       T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
96208                       A1 = E1;
96209                       E1 = D1;
96210                       D1 = bit_rol(C1, 10);
96211                       C1 = B1;
96212                       B1 = T;
96213                       T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
96214                       T = safe_add(T, x[i + rmd160_r2[j]]);
96215                       T = safe_add(T, rmd160_K2(j));
96216                       T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
96217                       A2 = E2;
96218                       E2 = D2;
96219                       D2 = bit_rol(C2, 10);
96220                       C2 = B2;
96221                       B2 = T;
96222                     }
96223
96224                     T = safe_add(h1, safe_add(C1, D2));
96225                     h1 = safe_add(h2, safe_add(D1, E2));
96226                     h2 = safe_add(h3, safe_add(E1, A2));
96227                     h3 = safe_add(h4, safe_add(A1, B2));
96228                     h4 = safe_add(h0, safe_add(B1, C2));
96229                     h0 = T;
96230                   }
96231
96232                   return [h0, h1, h2, h3, h4];
96233                 } // specific algorithm methods
96234
96235
96236                 function rmd160_f(j, x, y, z) {
96237                   return 0 <= j && j <= 15 ? x ^ y ^ z : 16 <= j && j <= 31 ? x & y | ~x & z : 32 <= j && j <= 47 ? (x | ~y) ^ z : 48 <= j && j <= 63 ? x & z | y & ~z : 64 <= j && j <= 79 ? x ^ (y | ~z) : 'rmd160_f: j out of range';
96238                 }
96239
96240                 function rmd160_K1(j) {
96241                   return 0 <= j && j <= 15 ? 0x00000000 : 16 <= j && j <= 31 ? 0x5a827999 : 32 <= j && j <= 47 ? 0x6ed9eba1 : 48 <= j && j <= 63 ? 0x8f1bbcdc : 64 <= j && j <= 79 ? 0xa953fd4e : 'rmd160_K1: j out of range';
96242                 }
96243
96244                 function rmd160_K2(j) {
96245                   return 0 <= j && j <= 15 ? 0x50a28be6 : 16 <= j && j <= 31 ? 0x5c4dd124 : 32 <= j && j <= 47 ? 0x6d703ef3 : 48 <= j && j <= 63 ? 0x7a6d76e9 : 64 <= j && j <= 79 ? 0x00000000 : 'rmd160_K2: j out of range';
96246                 }
96247               }
96248             }; // exposes Hashes
96249
96250             (function (window, undefined$1) {
96251               var freeExports = false;
96252
96253               {
96254                 freeExports = exports;
96255
96256                 if (exports && _typeof(commonjsGlobal) === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
96257                   window = commonjsGlobal;
96258                 }
96259               }
96260
96261               if (typeof undefined$1 === 'function' && _typeof(undefined$1.amd) === 'object' && undefined$1.amd) {
96262                 // define as an anonymous module, so, through path mapping, it can be aliased
96263                 undefined$1(function () {
96264                   return Hashes;
96265                 });
96266               } else if (freeExports) {
96267                 // in Node.js or RingoJS v0.8.0+
96268                 if (module && module.exports === freeExports) {
96269                   module.exports = Hashes;
96270                 } // in Narwhal or RingoJS v0.7.0-
96271                 else {
96272                     freeExports.Hashes = Hashes;
96273                   }
96274               } else {
96275                 // in a browser or Rhino
96276                 window.Hashes = Hashes;
96277               }
96278             })(this);
96279           })(); // IIFE
96280
96281         });
96282
96283         var sha1 = new hashes.SHA1(); // # xtend
96284
96285         var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
96286
96287         function xtend() {
96288           var target = {};
96289
96290           for (var i = 0; i < arguments.length; i++) {
96291             var source = arguments[i];
96292
96293             for (var key in source) {
96294               if (hasOwnProperty$1.call(source, key)) {
96295                 target[key] = source[key];
96296               }
96297             }
96298           }
96299
96300           return target;
96301         }
96302
96303         var ohauth = {};
96304
96305         ohauth.qsString = function (obj) {
96306           return Object.keys(obj).sort().map(function (key) {
96307             return ohauth.percentEncode(key) + '=' + ohauth.percentEncode(obj[key]);
96308           }).join('&');
96309         };
96310
96311         ohauth.stringQs = function (str) {
96312           return str.split('&').filter(function (pair) {
96313             return pair !== '';
96314           }).reduce(function (obj, pair) {
96315             var parts = pair.split('=');
96316             obj[decodeURIComponent(parts[0])] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
96317             return obj;
96318           }, {});
96319         };
96320
96321         ohauth.rawxhr = function (method, url, data, headers, callback) {
96322           var xhr = new XMLHttpRequest(),
96323               twoHundred = /^20\d$/;
96324
96325           xhr.onreadystatechange = function () {
96326             if (4 === xhr.readyState && 0 !== xhr.status) {
96327               if (twoHundred.test(xhr.status)) callback(null, xhr);else return callback(xhr, null);
96328             }
96329           };
96330
96331           xhr.onerror = function (e) {
96332             return callback(e, null);
96333           };
96334
96335           xhr.open(method, url, true);
96336
96337           for (var h in headers) {
96338             xhr.setRequestHeader(h, headers[h]);
96339           }
96340
96341           xhr.send(data);
96342           return xhr;
96343         };
96344
96345         ohauth.xhr = function (method, url, auth, data, options, callback) {
96346           var headers = options && options.header || {
96347             'Content-Type': 'application/x-www-form-urlencoded'
96348           };
96349           headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
96350           return ohauth.rawxhr(method, url, data, headers, callback);
96351         };
96352
96353         ohauth.nonce = function () {
96354           for (var o = ''; o.length < 6;) {
96355             o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
96356           }
96357
96358           return o;
96359         };
96360
96361         ohauth.authHeader = function (obj) {
96362           return Object.keys(obj).sort().map(function (key) {
96363             return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
96364           }).join(', ');
96365         };
96366
96367         ohauth.timestamp = function () {
96368           return ~~(+new Date() / 1000);
96369         };
96370
96371         ohauth.percentEncode = function (s) {
96372           return encodeURIComponent(s).replace(/\!/g, '%21').replace(/\'/g, '%27').replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
96373         };
96374
96375         ohauth.baseString = function (method, url, params) {
96376           if (params.oauth_signature) delete params.oauth_signature;
96377           return [method, ohauth.percentEncode(url), ohauth.percentEncode(ohauth.qsString(params))].join('&');
96378         };
96379
96380         ohauth.signature = function (oauth_secret, token_secret, baseString) {
96381           return sha1.b64_hmac(ohauth.percentEncode(oauth_secret) + '&' + ohauth.percentEncode(token_secret), baseString);
96382         };
96383         /**
96384          * Takes an options object for configuration (consumer_key,
96385          * consumer_secret, version, signature_method, token, token_secret)
96386          * and returns a function that generates the Authorization header
96387          * for given data.
96388          *
96389          * The returned function takes these parameters:
96390          * - method: GET/POST/...
96391          * - uri: full URI with protocol, port, path and query string
96392          * - extra_params: any extra parameters (that are passed in the POST data),
96393          *   can be an object or a from-urlencoded string.
96394          *
96395          * Returned function returns full OAuth header with "OAuth" string in it.
96396          */
96397
96398
96399         ohauth.headerGenerator = function (options) {
96400           options = options || {};
96401           var consumer_key = options.consumer_key || '',
96402               consumer_secret = options.consumer_secret || '',
96403               signature_method = options.signature_method || 'HMAC-SHA1',
96404               version = options.version || '1.0',
96405               token = options.token || '',
96406               token_secret = options.token_secret || '';
96407           return function (method, uri, extra_params) {
96408             method = method.toUpperCase();
96409
96410             if (typeof extra_params === 'string' && extra_params.length > 0) {
96411               extra_params = ohauth.stringQs(extra_params);
96412             }
96413
96414             var uri_parts = uri.split('?', 2),
96415                 base_uri = uri_parts[0];
96416             var query_params = uri_parts.length === 2 ? ohauth.stringQs(uri_parts[1]) : {};
96417             var oauth_params = {
96418               oauth_consumer_key: consumer_key,
96419               oauth_signature_method: signature_method,
96420               oauth_version: version,
96421               oauth_timestamp: ohauth.timestamp(),
96422               oauth_nonce: ohauth.nonce()
96423             };
96424             if (token) oauth_params.oauth_token = token;
96425             var all_params = xtend({}, oauth_params, query_params, extra_params),
96426                 base_str = ohauth.baseString(method, base_uri, all_params);
96427             oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
96428             return 'OAuth ' + ohauth.authHeader(oauth_params);
96429           };
96430         };
96431
96432         var ohauth_1 = ohauth;
96433
96434         var resolveUrl = createCommonjsModule(function (module, exports) {
96435           // Copyright 2014 Simon Lydell
96436           // X11 (“MIT”) Licensed. (See LICENSE.)
96437           void function (root, factory) {
96438             {
96439               module.exports = factory();
96440             }
96441           }(commonjsGlobal, function () {
96442             function resolveUrl()
96443             /* ...urls */
96444             {
96445               var numUrls = arguments.length;
96446
96447               if (numUrls === 0) {
96448                 throw new Error("resolveUrl requires at least one argument; got none.");
96449               }
96450
96451               var base = document.createElement("base");
96452               base.href = arguments[0];
96453
96454               if (numUrls === 1) {
96455                 return base.href;
96456               }
96457
96458               var head = document.getElementsByTagName("head")[0];
96459               head.insertBefore(base, head.firstChild);
96460               var a = document.createElement("a");
96461               var resolved;
96462
96463               for (var index = 1; index < numUrls; index++) {
96464                 a.href = arguments[index];
96465                 resolved = a.href;
96466                 base.href = resolved;
96467               }
96468
96469               head.removeChild(base);
96470               return resolved;
96471             }
96472
96473             return resolveUrl;
96474           });
96475         });
96476
96477         var assign = make_assign();
96478         var create$1 = make_create();
96479         var trim$1 = make_trim();
96480         var Global$5 = typeof window !== 'undefined' ? window : commonjsGlobal;
96481         var util = {
96482           assign: assign,
96483           create: create$1,
96484           trim: trim$1,
96485           bind: bind$1,
96486           slice: slice$1,
96487           each: each$7,
96488           map: map,
96489           pluck: pluck$1,
96490           isList: isList$1,
96491           isFunction: isFunction$1,
96492           isObject: isObject$1,
96493           Global: Global$5
96494         };
96495
96496         function make_assign() {
96497           if (Object.assign) {
96498             return Object.assign;
96499           } else {
96500             return function shimAssign(obj, props1, props2, etc) {
96501               for (var i = 1; i < arguments.length; i++) {
96502                 each$7(Object(arguments[i]), function (val, key) {
96503                   obj[key] = val;
96504                 });
96505               }
96506
96507               return obj;
96508             };
96509           }
96510         }
96511
96512         function make_create() {
96513           if (Object.create) {
96514             return function create(obj, assignProps1, assignProps2, etc) {
96515               var assignArgsList = slice$1(arguments, 1);
96516               return assign.apply(this, [Object.create(obj)].concat(assignArgsList));
96517             };
96518           } else {
96519             var F = function F() {}; // eslint-disable-line no-inner-declarations
96520
96521
96522             return function create(obj, assignProps1, assignProps2, etc) {
96523               var assignArgsList = slice$1(arguments, 1);
96524               F.prototype = obj;
96525               return assign.apply(this, [new F()].concat(assignArgsList));
96526             };
96527           }
96528         }
96529
96530         function make_trim() {
96531           if (String.prototype.trim) {
96532             return function trim(str) {
96533               return String.prototype.trim.call(str);
96534             };
96535           } else {
96536             return function trim(str) {
96537               return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
96538             };
96539           }
96540         }
96541
96542         function bind$1(obj, fn) {
96543           return function () {
96544             return fn.apply(obj, Array.prototype.slice.call(arguments, 0));
96545           };
96546         }
96547
96548         function slice$1(arr, index) {
96549           return Array.prototype.slice.call(arr, index || 0);
96550         }
96551
96552         function each$7(obj, fn) {
96553           pluck$1(obj, function (val, key) {
96554             fn(val, key);
96555             return false;
96556           });
96557         }
96558
96559         function map(obj, fn) {
96560           var res = isList$1(obj) ? [] : {};
96561           pluck$1(obj, function (v, k) {
96562             res[k] = fn(v, k);
96563             return false;
96564           });
96565           return res;
96566         }
96567
96568         function pluck$1(obj, fn) {
96569           if (isList$1(obj)) {
96570             for (var i = 0; i < obj.length; i++) {
96571               if (fn(obj[i], i)) {
96572                 return obj[i];
96573               }
96574             }
96575           } else {
96576             for (var key in obj) {
96577               if (obj.hasOwnProperty(key)) {
96578                 if (fn(obj[key], key)) {
96579                   return obj[key];
96580                 }
96581               }
96582             }
96583           }
96584         }
96585
96586         function isList$1(val) {
96587           return val != null && typeof val != 'function' && typeof val.length == 'number';
96588         }
96589
96590         function isFunction$1(val) {
96591           return val && {}.toString.call(val) === '[object Function]';
96592         }
96593
96594         function isObject$1(val) {
96595           return val && {}.toString.call(val) === '[object Object]';
96596         }
96597
96598         var slice = util.slice;
96599         var pluck = util.pluck;
96600         var each$6 = util.each;
96601         var bind = util.bind;
96602         var create = util.create;
96603         var isList = util.isList;
96604         var isFunction = util.isFunction;
96605         var isObject = util.isObject;
96606         var storeEngine = {
96607           createStore: _createStore
96608         };
96609         var storeAPI = {
96610           version: '2.0.12',
96611           enabled: false,
96612           // get returns the value of the given key. If that value
96613           // is undefined, it returns optionalDefaultValue instead.
96614           get: function get(key, optionalDefaultValue) {
96615             var data = this.storage.read(this._namespacePrefix + key);
96616             return this._deserialize(data, optionalDefaultValue);
96617           },
96618           // set will store the given value at key and returns value.
96619           // Calling set with value === undefined is equivalent to calling remove.
96620           set: function set(key, value) {
96621             if (value === undefined) {
96622               return this.remove(key);
96623             }
96624
96625             this.storage.write(this._namespacePrefix + key, this._serialize(value));
96626             return value;
96627           },
96628           // remove deletes the key and value stored at the given key.
96629           remove: function remove(key) {
96630             this.storage.remove(this._namespacePrefix + key);
96631           },
96632           // each will call the given callback once for each key-value pair
96633           // in this store.
96634           each: function each(callback) {
96635             var self = this;
96636             this.storage.each(function (val, namespacedKey) {
96637               callback.call(self, self._deserialize(val), (namespacedKey || '').replace(self._namespaceRegexp, ''));
96638             });
96639           },
96640           // clearAll will remove all the stored key-value pairs in this store.
96641           clearAll: function clearAll() {
96642             this.storage.clearAll();
96643           },
96644           // additional functionality that can't live in plugins
96645           // ---------------------------------------------------
96646           // hasNamespace returns true if this store instance has the given namespace.
96647           hasNamespace: function hasNamespace(namespace) {
96648             return this._namespacePrefix == '__storejs_' + namespace + '_';
96649           },
96650           // createStore creates a store.js instance with the first
96651           // functioning storage in the list of storage candidates,
96652           // and applies the the given mixins to the instance.
96653           createStore: function createStore() {
96654             return _createStore.apply(this, arguments);
96655           },
96656           addPlugin: function addPlugin(plugin) {
96657             this._addPlugin(plugin);
96658           },
96659           namespace: function namespace(_namespace) {
96660             return _createStore(this.storage, this.plugins, _namespace);
96661           }
96662         };
96663
96664         function _warn() {
96665           var _console = typeof console == 'undefined' ? null : console;
96666
96667           if (!_console) {
96668             return;
96669           }
96670
96671           var fn = _console.warn ? _console.warn : _console.log;
96672           fn.apply(_console, arguments);
96673         }
96674
96675         function _createStore(storages, plugins, namespace) {
96676           if (!namespace) {
96677             namespace = '';
96678           }
96679
96680           if (storages && !isList(storages)) {
96681             storages = [storages];
96682           }
96683
96684           if (plugins && !isList(plugins)) {
96685             plugins = [plugins];
96686           }
96687
96688           var namespacePrefix = namespace ? '__storejs_' + namespace + '_' : '';
96689           var namespaceRegexp = namespace ? new RegExp('^' + namespacePrefix) : null;
96690           var legalNamespaces = /^[a-zA-Z0-9_\-]*$/; // alpha-numeric + underscore and dash
96691
96692           if (!legalNamespaces.test(namespace)) {
96693             throw new Error('store.js namespaces can only have alphanumerics + underscores and dashes');
96694           }
96695
96696           var _privateStoreProps = {
96697             _namespacePrefix: namespacePrefix,
96698             _namespaceRegexp: namespaceRegexp,
96699             _testStorage: function _testStorage(storage) {
96700               try {
96701                 var testStr = '__storejs__test__';
96702                 storage.write(testStr, testStr);
96703                 var ok = storage.read(testStr) === testStr;
96704                 storage.remove(testStr);
96705                 return ok;
96706               } catch (e) {
96707                 return false;
96708               }
96709             },
96710             _assignPluginFnProp: function _assignPluginFnProp(pluginFnProp, propName) {
96711               var oldFn = this[propName];
96712
96713               this[propName] = function pluginFn() {
96714                 var args = slice(arguments, 0);
96715                 var self = this; // super_fn calls the old function which was overwritten by
96716                 // this mixin.
96717
96718                 function super_fn() {
96719                   if (!oldFn) {
96720                     return;
96721                   }
96722
96723                   each$6(arguments, function (arg, i) {
96724                     args[i] = arg;
96725                   });
96726                   return oldFn.apply(self, args);
96727                 } // Give mixing function access to super_fn by prefixing all mixin function
96728                 // arguments with super_fn.
96729
96730
96731                 var newFnArgs = [super_fn].concat(args);
96732                 return pluginFnProp.apply(self, newFnArgs);
96733               };
96734             },
96735             _serialize: function _serialize(obj) {
96736               return JSON.stringify(obj);
96737             },
96738             _deserialize: function _deserialize(strVal, defaultVal) {
96739               if (!strVal) {
96740                 return defaultVal;
96741               } // It is possible that a raw string value has been previously stored
96742               // in a storage without using store.js, meaning it will be a raw
96743               // string value instead of a JSON serialized string. By defaulting
96744               // to the raw string value in case of a JSON parse error, we allow
96745               // for past stored values to be forwards-compatible with store.js
96746
96747
96748               var val = '';
96749
96750               try {
96751                 val = JSON.parse(strVal);
96752               } catch (e) {
96753                 val = strVal;
96754               }
96755
96756               return val !== undefined ? val : defaultVal;
96757             },
96758             _addStorage: function _addStorage(storage) {
96759               if (this.enabled) {
96760                 return;
96761               }
96762
96763               if (this._testStorage(storage)) {
96764                 this.storage = storage;
96765                 this.enabled = true;
96766               }
96767             },
96768             _addPlugin: function _addPlugin(plugin) {
96769               var self = this; // If the plugin is an array, then add all plugins in the array.
96770               // This allows for a plugin to depend on other plugins.
96771
96772               if (isList(plugin)) {
96773                 each$6(plugin, function (plugin) {
96774                   self._addPlugin(plugin);
96775                 });
96776                 return;
96777               } // Keep track of all plugins we've seen so far, so that we
96778               // don't add any of them twice.
96779
96780
96781               var seenPlugin = pluck(this.plugins, function (seenPlugin) {
96782                 return plugin === seenPlugin;
96783               });
96784
96785               if (seenPlugin) {
96786                 return;
96787               }
96788
96789               this.plugins.push(plugin); // Check that the plugin is properly formed
96790
96791               if (!isFunction(plugin)) {
96792                 throw new Error('Plugins must be function values that return objects');
96793               }
96794
96795               var pluginProperties = plugin.call(this);
96796
96797               if (!isObject(pluginProperties)) {
96798                 throw new Error('Plugins must return an object of function properties');
96799               } // Add the plugin function properties to this store instance.
96800
96801
96802               each$6(pluginProperties, function (pluginFnProp, propName) {
96803                 if (!isFunction(pluginFnProp)) {
96804                   throw new Error('Bad plugin property: ' + propName + ' from plugin ' + plugin.name + '. Plugins should only return functions.');
96805                 }
96806
96807                 self._assignPluginFnProp(pluginFnProp, propName);
96808               });
96809             },
96810             // Put deprecated properties in the private API, so as to not expose it to accidential
96811             // discovery through inspection of the store object.
96812             // Deprecated: addStorage
96813             addStorage: function addStorage(storage) {
96814               _warn('store.addStorage(storage) is deprecated. Use createStore([storages])');
96815
96816               this._addStorage(storage);
96817             }
96818           };
96819           var store = create(_privateStoreProps, storeAPI, {
96820             plugins: []
96821           });
96822           store.raw = {};
96823           each$6(store, function (prop, propName) {
96824             if (isFunction(prop)) {
96825               store.raw[propName] = bind(store, prop);
96826             }
96827           });
96828           each$6(storages, function (storage) {
96829             store._addStorage(storage);
96830           });
96831           each$6(plugins, function (plugin) {
96832             store._addPlugin(plugin);
96833           });
96834           return store;
96835         }
96836
96837         var Global$4 = util.Global;
96838         var localStorage_1 = {
96839           name: 'localStorage',
96840           read: read$5,
96841           write: write$5,
96842           each: each$5,
96843           remove: remove$5,
96844           clearAll: clearAll$5
96845         };
96846
96847         function localStorage$1() {
96848           return Global$4.localStorage;
96849         }
96850
96851         function read$5(key) {
96852           return localStorage$1().getItem(key);
96853         }
96854
96855         function write$5(key, data) {
96856           return localStorage$1().setItem(key, data);
96857         }
96858
96859         function each$5(fn) {
96860           for (var i = localStorage$1().length - 1; i >= 0; i--) {
96861             var key = localStorage$1().key(i);
96862             fn(read$5(key), key);
96863           }
96864         }
96865
96866         function remove$5(key) {
96867           return localStorage$1().removeItem(key);
96868         }
96869
96870         function clearAll$5() {
96871           return localStorage$1().clear();
96872         }
96873
96874         // versions 6 and 7, where no localStorage, etc
96875         // is available.
96876
96877         var Global$3 = util.Global;
96878         var oldFFGlobalStorage = {
96879           name: 'oldFF-globalStorage',
96880           read: read$4,
96881           write: write$4,
96882           each: each$4,
96883           remove: remove$4,
96884           clearAll: clearAll$4
96885         };
96886         var globalStorage = Global$3.globalStorage;
96887
96888         function read$4(key) {
96889           return globalStorage[key];
96890         }
96891
96892         function write$4(key, data) {
96893           globalStorage[key] = data;
96894         }
96895
96896         function each$4(fn) {
96897           for (var i = globalStorage.length - 1; i >= 0; i--) {
96898             var key = globalStorage.key(i);
96899             fn(globalStorage[key], key);
96900           }
96901         }
96902
96903         function remove$4(key) {
96904           return globalStorage.removeItem(key);
96905         }
96906
96907         function clearAll$4() {
96908           each$4(function (key, _) {
96909             delete globalStorage[key];
96910           });
96911         }
96912
96913         // versions 6 and 7, where no localStorage, sessionStorage, etc
96914         // is available.
96915
96916         var Global$2 = util.Global;
96917         var oldIEUserDataStorage = {
96918           name: 'oldIE-userDataStorage',
96919           write: write$3,
96920           read: read$3,
96921           each: each$3,
96922           remove: remove$3,
96923           clearAll: clearAll$3
96924         };
96925         var storageName = 'storejs';
96926         var doc$1 = Global$2.document;
96927
96928         var _withStorageEl = _makeIEStorageElFunction();
96929
96930         var disable = (Global$2.navigator ? Global$2.navigator.userAgent : '').match(/ (MSIE 8|MSIE 9|MSIE 10)\./); // MSIE 9.x, MSIE 10.x
96931
96932         function write$3(unfixedKey, data) {
96933           if (disable) {
96934             return;
96935           }
96936
96937           var fixedKey = fixKey(unfixedKey);
96938
96939           _withStorageEl(function (storageEl) {
96940             storageEl.setAttribute(fixedKey, data);
96941             storageEl.save(storageName);
96942           });
96943         }
96944
96945         function read$3(unfixedKey) {
96946           if (disable) {
96947             return;
96948           }
96949
96950           var fixedKey = fixKey(unfixedKey);
96951           var res = null;
96952
96953           _withStorageEl(function (storageEl) {
96954             res = storageEl.getAttribute(fixedKey);
96955           });
96956
96957           return res;
96958         }
96959
96960         function each$3(callback) {
96961           _withStorageEl(function (storageEl) {
96962             var attributes = storageEl.XMLDocument.documentElement.attributes;
96963
96964             for (var i = attributes.length - 1; i >= 0; i--) {
96965               var attr = attributes[i];
96966               callback(storageEl.getAttribute(attr.name), attr.name);
96967             }
96968           });
96969         }
96970
96971         function remove$3(unfixedKey) {
96972           var fixedKey = fixKey(unfixedKey);
96973
96974           _withStorageEl(function (storageEl) {
96975             storageEl.removeAttribute(fixedKey);
96976             storageEl.save(storageName);
96977           });
96978         }
96979
96980         function clearAll$3() {
96981           _withStorageEl(function (storageEl) {
96982             var attributes = storageEl.XMLDocument.documentElement.attributes;
96983             storageEl.load(storageName);
96984
96985             for (var i = attributes.length - 1; i >= 0; i--) {
96986               storageEl.removeAttribute(attributes[i].name);
96987             }
96988
96989             storageEl.save(storageName);
96990           });
96991         } // Helpers
96992         //////////
96993         // In IE7, keys cannot start with a digit or contain certain chars.
96994         // See https://github.com/marcuswestin/store.js/issues/40
96995         // See https://github.com/marcuswestin/store.js/issues/83
96996
96997
96998         var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
96999
97000         function fixKey(key) {
97001           return key.replace(/^\d/, '___$&').replace(forbiddenCharsRegex, '___');
97002         }
97003
97004         function _makeIEStorageElFunction() {
97005           if (!doc$1 || !doc$1.documentElement || !doc$1.documentElement.addBehavior) {
97006             return null;
97007           }
97008
97009           var scriptTag = 'script',
97010               storageOwner,
97011               storageContainer,
97012               storageEl; // Since #userData storage applies only to specific paths, we need to
97013           // somehow link our data to a specific path.  We choose /favicon.ico
97014           // as a pretty safe option, since all browsers already make a request to
97015           // this URL anyway and being a 404 will not hurt us here.  We wrap an
97016           // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
97017           // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
97018           // since the iframe access rules appear to allow direct access and
97019           // manipulation of the document element, even for a 404 page.  This
97020           // document can be used instead of the current document (which would
97021           // have been limited to the current path) to perform #userData storage.
97022
97023           try {
97024             /* global ActiveXObject */
97025             storageContainer = new ActiveXObject('htmlfile');
97026             storageContainer.open();
97027             storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src="/favicon.ico"></iframe>');
97028             storageContainer.close();
97029             storageOwner = storageContainer.w.frames[0].document;
97030             storageEl = storageOwner.createElement('div');
97031           } catch (e) {
97032             // somehow ActiveXObject instantiation failed (perhaps some special
97033             // security settings or otherwse), fall back to per-path storage
97034             storageEl = doc$1.createElement('div');
97035             storageOwner = doc$1.body;
97036           }
97037
97038           return function (storeFunction) {
97039             var args = [].slice.call(arguments, 0);
97040             args.unshift(storageEl); // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
97041             // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
97042
97043             storageOwner.appendChild(storageEl);
97044             storageEl.addBehavior('#default#userData');
97045             storageEl.load(storageName);
97046             storeFunction.apply(this, args);
97047             storageOwner.removeChild(storageEl);
97048             return;
97049           };
97050         }
97051
97052         // doesn't work but cookies do. This implementation is adopted from
97053         // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
97054
97055         var Global$1 = util.Global;
97056         var trim = util.trim;
97057         var cookieStorage = {
97058           name: 'cookieStorage',
97059           read: read$2,
97060           write: write$2,
97061           each: each$2,
97062           remove: remove$2,
97063           clearAll: clearAll$2
97064         };
97065         var doc = Global$1.document;
97066
97067         function read$2(key) {
97068           if (!key || !_has(key)) {
97069             return null;
97070           }
97071
97072           var regexpStr = "(?:^|.*;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
97073           return unescape(doc.cookie.replace(new RegExp(regexpStr), "$1"));
97074         }
97075
97076         function each$2(callback) {
97077           var cookies = doc.cookie.split(/; ?/g);
97078
97079           for (var i = cookies.length - 1; i >= 0; i--) {
97080             if (!trim(cookies[i])) {
97081               continue;
97082             }
97083
97084             var kvp = cookies[i].split('=');
97085             var key = unescape(kvp[0]);
97086             var val = unescape(kvp[1]);
97087             callback(val, key);
97088           }
97089         }
97090
97091         function write$2(key, data) {
97092           if (!key) {
97093             return;
97094           }
97095
97096           doc.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
97097         }
97098
97099         function remove$2(key) {
97100           if (!key || !_has(key)) {
97101             return;
97102           }
97103
97104           doc.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
97105         }
97106
97107         function clearAll$2() {
97108           each$2(function (_, key) {
97109             remove$2(key);
97110           });
97111         }
97112
97113         function _has(key) {
97114           return new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(doc.cookie);
97115         }
97116
97117         var Global = util.Global;
97118         var sessionStorage_1 = {
97119           name: 'sessionStorage',
97120           read: read$1,
97121           write: write$1,
97122           each: each$1,
97123           remove: remove$1,
97124           clearAll: clearAll$1
97125         };
97126
97127         function sessionStorage() {
97128           return Global.sessionStorage;
97129         }
97130
97131         function read$1(key) {
97132           return sessionStorage().getItem(key);
97133         }
97134
97135         function write$1(key, data) {
97136           return sessionStorage().setItem(key, data);
97137         }
97138
97139         function each$1(fn) {
97140           for (var i = sessionStorage().length - 1; i >= 0; i--) {
97141             var key = sessionStorage().key(i);
97142             fn(read$1(key), key);
97143           }
97144         }
97145
97146         function remove$1(key) {
97147           return sessionStorage().removeItem(key);
97148         }
97149
97150         function clearAll$1() {
97151           return sessionStorage().clear();
97152         }
97153
97154         // memoryStorage is a useful last fallback to ensure that the store
97155         // is functions (meaning store.get(), store.set(), etc will all function).
97156         // However, stored values will not persist when the browser navigates to
97157         // a new page or reloads the current page.
97158         var memoryStorage_1 = {
97159           name: 'memoryStorage',
97160           read: read,
97161           write: write,
97162           each: each,
97163           remove: remove,
97164           clearAll: clearAll
97165         };
97166         var memoryStorage = {};
97167
97168         function read(key) {
97169           return memoryStorage[key];
97170         }
97171
97172         function write(key, data) {
97173           memoryStorage[key] = data;
97174         }
97175
97176         function each(callback) {
97177           for (var key in memoryStorage) {
97178             if (memoryStorage.hasOwnProperty(key)) {
97179               callback(memoryStorage[key], key);
97180             }
97181           }
97182         }
97183
97184         function remove(key) {
97185           delete memoryStorage[key];
97186         }
97187
97188         function clearAll(key) {
97189           memoryStorage = {};
97190         }
97191
97192         var all = [// Listed in order of usage preference
97193         localStorage_1, oldFFGlobalStorage, oldIEUserDataStorage, cookieStorage, sessionStorage_1, memoryStorage_1];
97194
97195         /* eslint-disable */
97196         //  json2.js
97197         //  2016-10-28
97198         //  Public Domain.
97199         //  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
97200         //  See http://www.JSON.org/js.html
97201         //  This code should be minified before deployment.
97202         //  See http://javascript.crockford.com/jsmin.html
97203         //  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
97204         //  NOT CONTROL.
97205         //  This file creates a global JSON object containing two methods: stringify
97206         //  and parse. This file provides the ES5 JSON capability to ES3 systems.
97207         //  If a project might run on IE8 or earlier, then this file should be included.
97208         //  This file does nothing on ES5 systems.
97209         //      JSON.stringify(value, replacer, space)
97210         //          value       any JavaScript value, usually an object or array.
97211         //          replacer    an optional parameter that determines how object
97212         //                      values are stringified for objects. It can be a
97213         //                      function or an array of strings.
97214         //          space       an optional parameter that specifies the indentation
97215         //                      of nested structures. If it is omitted, the text will
97216         //                      be packed without extra whitespace. If it is a number,
97217         //                      it will specify the number of spaces to indent at each
97218         //                      level. If it is a string (such as "\t" or "&nbsp;"),
97219         //                      it contains the characters used to indent at each level.
97220         //          This method produces a JSON text from a JavaScript value.
97221         //          When an object value is found, if the object contains a toJSON
97222         //          method, its toJSON method will be called and the result will be
97223         //          stringified. A toJSON method does not serialize: it returns the
97224         //          value represented by the name/value pair that should be serialized,
97225         //          or undefined if nothing should be serialized. The toJSON method
97226         //          will be passed the key associated with the value, and this will be
97227         //          bound to the value.
97228         //          For example, this would serialize Dates as ISO strings.
97229         //              Date.prototype.toJSON = function (key) {
97230         //                  function f(n) {
97231         //                      // Format integers to have at least two digits.
97232         //                      return (n < 10)
97233         //                          ? "0" + n
97234         //                          : n;
97235         //                  }
97236         //                  return this.getUTCFullYear()   + "-" +
97237         //                       f(this.getUTCMonth() + 1) + "-" +
97238         //                       f(this.getUTCDate())      + "T" +
97239         //                       f(this.getUTCHours())     + ":" +
97240         //                       f(this.getUTCMinutes())   + ":" +
97241         //                       f(this.getUTCSeconds())   + "Z";
97242         //              };
97243         //          You can provide an optional replacer method. It will be passed the
97244         //          key and value of each member, with this bound to the containing
97245         //          object. The value that is returned from your method will be
97246         //          serialized. If your method returns undefined, then the member will
97247         //          be excluded from the serialization.
97248         //          If the replacer parameter is an array of strings, then it will be
97249         //          used to select the members to be serialized. It filters the results
97250         //          such that only members with keys listed in the replacer array are
97251         //          stringified.
97252         //          Values that do not have JSON representations, such as undefined or
97253         //          functions, will not be serialized. Such values in objects will be
97254         //          dropped; in arrays they will be replaced with null. You can use
97255         //          a replacer function to replace those with JSON values.
97256         //          JSON.stringify(undefined) returns undefined.
97257         //          The optional space parameter produces a stringification of the
97258         //          value that is filled with line breaks and indentation to make it
97259         //          easier to read.
97260         //          If the space parameter is a non-empty string, then that string will
97261         //          be used for indentation. If the space parameter is a number, then
97262         //          the indentation will be that many spaces.
97263         //          Example:
97264         //          text = JSON.stringify(["e", {pluribus: "unum"}]);
97265         //          // text is '["e",{"pluribus":"unum"}]'
97266         //          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
97267         //          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
97268         //          text = JSON.stringify([new Date()], function (key, value) {
97269         //              return this[key] instanceof Date
97270         //                  ? "Date(" + this[key] + ")"
97271         //                  : value;
97272         //          });
97273         //          // text is '["Date(---current time---)"]'
97274         //      JSON.parse(text, reviver)
97275         //          This method parses a JSON text to produce an object or array.
97276         //          It can throw a SyntaxError exception.
97277         //          The optional reviver parameter is a function that can filter and
97278         //          transform the results. It receives each of the keys and values,
97279         //          and its return value is used instead of the original value.
97280         //          If it returns what it received, then the structure is not modified.
97281         //          If it returns undefined then the member is deleted.
97282         //          Example:
97283         //          // Parse the text. Values that look like ISO date strings will
97284         //          // be converted to Date objects.
97285         //          myData = JSON.parse(text, function (key, value) {
97286         //              var a;
97287         //              if (typeof value === "string") {
97288         //                  a =
97289         //   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
97290         //                  if (a) {
97291         //                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
97292         //                          +a[5], +a[6]));
97293         //                  }
97294         //              }
97295         //              return value;
97296         //          });
97297         //          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
97298         //              var d;
97299         //              if (typeof value === "string" &&
97300         //                      value.slice(0, 5) === "Date(" &&
97301         //                      value.slice(-1) === ")") {
97302         //                  d = new Date(value.slice(5, -1));
97303         //                  if (d) {
97304         //                      return d;
97305         //                  }
97306         //              }
97307         //              return value;
97308         //          });
97309         //  This is a reference implementation. You are free to copy, modify, or
97310         //  redistribute.
97311
97312         /*jslint
97313             eval, for, this
97314         */
97315
97316         /*property
97317             JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
97318             getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
97319             lastIndex, length, parse, prototype, push, replace, slice, stringify,
97320             test, toJSON, toString, valueOf
97321         */
97322         // Create a JSON object only if one does not already exist. We create the
97323         // methods in a closure to avoid creating global variables.
97324         if ((typeof JSON === "undefined" ? "undefined" : _typeof(JSON)) !== "object") {
97325           JSON = {};
97326         }
97327
97328         (function () {
97329
97330           var rx_one = /^[\],:{}\s]*$/;
97331           var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
97332           var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
97333           var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
97334           var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
97335           var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
97336
97337           function f(n) {
97338             // Format integers to have at least two digits.
97339             return n < 10 ? "0" + n : n;
97340           }
97341
97342           function this_value() {
97343             return this.valueOf();
97344           }
97345
97346           if (typeof Date.prototype.toJSON !== "function") {
97347             Date.prototype.toJSON = function () {
97348               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;
97349             };
97350
97351             Boolean.prototype.toJSON = this_value;
97352             Number.prototype.toJSON = this_value;
97353             String.prototype.toJSON = this_value;
97354           }
97355
97356           var gap;
97357           var indent;
97358           var meta;
97359           var rep;
97360
97361           function quote(string) {
97362             // If the string contains no control characters, no quote characters, and no
97363             // backslash characters, then we can safely slap some quotes around it.
97364             // Otherwise we must also replace the offending characters with safe escape
97365             // sequences.
97366             rx_escapable.lastIndex = 0;
97367             return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) {
97368               var c = meta[a];
97369               return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
97370             }) + "\"" : "\"" + string + "\"";
97371           }
97372
97373           function str(key, holder) {
97374             // Produce a string from holder[key].
97375             var i; // The loop counter.
97376
97377             var k; // The member key.
97378
97379             var v; // The member value.
97380
97381             var length;
97382             var mind = gap;
97383             var partial;
97384             var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value.
97385
97386             if (value && _typeof(value) === "object" && typeof value.toJSON === "function") {
97387               value = value.toJSON(key);
97388             } // If we were called with a replacer function, then call the replacer to
97389             // obtain a replacement value.
97390
97391
97392             if (typeof rep === "function") {
97393               value = rep.call(holder, key, value);
97394             } // What happens next depends on the value's type.
97395
97396
97397             switch (_typeof(value)) {
97398               case "string":
97399                 return quote(value);
97400
97401               case "number":
97402                 // JSON numbers must be finite. Encode non-finite numbers as null.
97403                 return isFinite(value) ? String(value) : "null";
97404
97405               case "boolean":
97406               case "null":
97407                 // If the value is a boolean or null, convert it to a string. Note:
97408                 // typeof null does not produce "null". The case is included here in
97409                 // the remote chance that this gets fixed someday.
97410                 return String(value);
97411               // If the type is "object", we might be dealing with an object or an array or
97412               // null.
97413
97414               case "object":
97415                 // Due to a specification blunder in ECMAScript, typeof null is "object",
97416                 // so watch out for that case.
97417                 if (!value) {
97418                   return "null";
97419                 } // Make an array to hold the partial results of stringifying this object value.
97420
97421
97422                 gap += indent;
97423                 partial = []; // Is the value an array?
97424
97425                 if (Object.prototype.toString.apply(value) === "[object Array]") {
97426                   // The value is an array. Stringify every element. Use null as a placeholder
97427                   // for non-JSON values.
97428                   length = value.length;
97429
97430                   for (i = 0; i < length; i += 1) {
97431                     partial[i] = str(i, value) || "null";
97432                   } // Join all of the elements together, separated with commas, and wrap them in
97433                   // brackets.
97434
97435
97436                   v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]";
97437                   gap = mind;
97438                   return v;
97439                 } // If the replacer is an array, use it to select the members to be stringified.
97440
97441
97442                 if (rep && _typeof(rep) === "object") {
97443                   length = rep.length;
97444
97445                   for (i = 0; i < length; i += 1) {
97446                     if (typeof rep[i] === "string") {
97447                       k = rep[i];
97448                       v = str(k, value);
97449
97450                       if (v) {
97451                         partial.push(quote(k) + (gap ? ": " : ":") + v);
97452                       }
97453                     }
97454                   }
97455                 } else {
97456                   // Otherwise, iterate through all of the keys in the object.
97457                   for (k in value) {
97458                     if (Object.prototype.hasOwnProperty.call(value, k)) {
97459                       v = str(k, value);
97460
97461                       if (v) {
97462                         partial.push(quote(k) + (gap ? ": " : ":") + v);
97463                       }
97464                     }
97465                   }
97466                 } // Join all of the member texts together, separated with commas,
97467                 // and wrap them in braces.
97468
97469
97470                 v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}";
97471                 gap = mind;
97472                 return v;
97473             }
97474           } // If the JSON object does not yet have a stringify method, give it one.
97475
97476
97477           if (typeof JSON.stringify !== "function") {
97478             meta = {
97479               // table of character substitutions
97480               "\b": "\\b",
97481               "\t": "\\t",
97482               "\n": "\\n",
97483               "\f": "\\f",
97484               "\r": "\\r",
97485               "\"": "\\\"",
97486               "\\": "\\\\"
97487             };
97488
97489             JSON.stringify = function (value, replacer, space) {
97490               // The stringify method takes a value and an optional replacer, and an optional
97491               // space parameter, and returns a JSON text. The replacer can be a function
97492               // that can replace values, or an array of strings that will select the keys.
97493               // A default replacer method can be provided. Use of the space parameter can
97494               // produce text that is more easily readable.
97495               var i;
97496               gap = "";
97497               indent = ""; // If the space parameter is a number, make an indent string containing that
97498               // many spaces.
97499
97500               if (typeof space === "number") {
97501                 for (i = 0; i < space; i += 1) {
97502                   indent += " ";
97503                 } // If the space parameter is a string, it will be used as the indent string.
97504
97505               } else if (typeof space === "string") {
97506                 indent = space;
97507               } // If there is a replacer, it must be a function or an array.
97508               // Otherwise, throw an error.
97509
97510
97511               rep = replacer;
97512
97513               if (replacer && typeof replacer !== "function" && (_typeof(replacer) !== "object" || typeof replacer.length !== "number")) {
97514                 throw new Error("JSON.stringify");
97515               } // Make a fake root object containing our value under the key of "".
97516               // Return the result of stringifying the value.
97517
97518
97519               return str("", {
97520                 "": value
97521               });
97522             };
97523           } // If the JSON object does not yet have a parse method, give it one.
97524
97525
97526           if (typeof JSON.parse !== "function") {
97527             JSON.parse = function (text, reviver) {
97528               // The parse method takes a text and an optional reviver function, and returns
97529               // a JavaScript value if the text is a valid JSON text.
97530               var j;
97531
97532               function walk(holder, key) {
97533                 // The walk method is used to recursively walk the resulting structure so
97534                 // that modifications can be made.
97535                 var k;
97536                 var v;
97537                 var value = holder[key];
97538
97539                 if (value && _typeof(value) === "object") {
97540                   for (k in value) {
97541                     if (Object.prototype.hasOwnProperty.call(value, k)) {
97542                       v = walk(value, k);
97543
97544                       if (v !== undefined) {
97545                         value[k] = v;
97546                       } else {
97547                         delete value[k];
97548                       }
97549                     }
97550                   }
97551                 }
97552
97553                 return reviver.call(holder, key, value);
97554               } // Parsing happens in four stages. In the first stage, we replace certain
97555               // Unicode characters with escape sequences. JavaScript handles many characters
97556               // incorrectly, either silently deleting them, or treating them as line endings.
97557
97558
97559               text = String(text);
97560               rx_dangerous.lastIndex = 0;
97561
97562               if (rx_dangerous.test(text)) {
97563                 text = text.replace(rx_dangerous, function (a) {
97564                   return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
97565                 });
97566               } // In the second stage, we run the text against regular expressions that look
97567               // for non-JSON patterns. We are especially concerned with "()" and "new"
97568               // because they can cause invocation, and "=" because it can cause mutation.
97569               // But just to be safe, we want to reject all unexpected forms.
97570               // We split the second stage into 4 regexp operations in order to work around
97571               // crippling inefficiencies in IE's and Safari's regexp engines. First we
97572               // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
97573               // replace all simple value tokens with "]" characters. Third, we delete all
97574               // open brackets that follow a colon or comma or that begin the text. Finally,
97575               // we look to see that the remaining characters are only whitespace or "]" or
97576               // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
97577
97578
97579               if (rx_one.test(text.replace(rx_two, "@").replace(rx_three, "]").replace(rx_four, ""))) {
97580                 // In the third stage we use the eval function to compile the text into a
97581                 // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
97582                 // in JavaScript: it can begin a block or an object literal. We wrap the text
97583                 // in parens to eliminate the ambiguity.
97584                 j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing
97585                 // each name/value pair to a reviver function for possible transformation.
97586
97587                 return typeof reviver === "function" ? walk({
97588                   "": j
97589                 }, "") : j;
97590               } // If the text is not JSON parseable, then a SyntaxError is thrown.
97591
97592
97593               throw new SyntaxError("JSON.parse");
97594             };
97595           }
97596         })();
97597
97598         var json2 = json2Plugin;
97599
97600         function json2Plugin() {
97601           return {};
97602         }
97603
97604         var plugins = [json2];
97605         var store_legacy = storeEngine.createStore(all, plugins);
97606
97607         var immutable = extend;
97608         var hasOwnProperty = Object.prototype.hasOwnProperty;
97609
97610         function extend() {
97611           var target = {};
97612
97613           for (var i = 0; i < arguments.length; i++) {
97614             var source = arguments[i];
97615
97616             for (var key in source) {
97617               if (hasOwnProperty.call(source, key)) {
97618                 target[key] = source[key];
97619               }
97620             }
97621           }
97622
97623           return target;
97624         }
97625
97626         //
97627         // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
97628         // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
97629         // does not support custom headers, which this uses everywhere.
97630
97631
97632         var osmAuth = function osmAuth(o) {
97633           var oauth = {}; // authenticated users will also have a request token secret, but it's
97634           // not used in transactions with the server
97635
97636           oauth.authenticated = function () {
97637             return !!(token('oauth_token') && token('oauth_token_secret'));
97638           };
97639
97640           oauth.logout = function () {
97641             token('oauth_token', '');
97642             token('oauth_token_secret', '');
97643             token('oauth_request_token_secret', '');
97644             return oauth;
97645           }; // TODO: detect lack of click event
97646
97647
97648           oauth.authenticate = function (callback) {
97649             if (oauth.authenticated()) return callback();
97650             oauth.logout(); // ## Getting a request token
97651
97652             var params = timenonce(getAuth(o)),
97653                 url = o.url + '/oauth/request_token';
97654             params.oauth_signature = ohauth_1.signature(o.oauth_secret, '', ohauth_1.baseString('POST', url, params));
97655
97656             if (!o.singlepage) {
97657               // Create a 600x550 popup window in the center of the screen
97658               var w = 600,
97659                   h = 550,
97660                   settings = [['width', w], ['height', h], ['left', screen.width / 2 - w / 2], ['top', screen.height / 2 - h / 2]].map(function (x) {
97661                 return x.join('=');
97662               }).join(','),
97663                   popup = window.open('about:blank', 'oauth_window', settings);
97664               oauth.popupWindow = popup;
97665
97666               if (!popup) {
97667                 var error = new Error('Popup was blocked');
97668                 error.status = 'popup-blocked';
97669                 throw error;
97670               }
97671             } // Request a request token. When this is complete, the popup
97672             // window is redirected to OSM's authorization page.
97673
97674
97675             ohauth_1.xhr('POST', url, params, null, {}, reqTokenDone);
97676             o.loading();
97677
97678             function reqTokenDone(err, xhr) {
97679               o.done();
97680               if (err) return callback(err);
97681               var resp = ohauth_1.stringQs(xhr.response);
97682               token('oauth_request_token_secret', resp.oauth_token_secret);
97683               var authorize_url = o.url + '/oauth/authorize?' + ohauth_1.qsString({
97684                 oauth_token: resp.oauth_token,
97685                 oauth_callback: resolveUrl(o.landing)
97686               });
97687
97688               if (o.singlepage) {
97689                 location.href = authorize_url;
97690               } else {
97691                 popup.location = authorize_url;
97692               }
97693             } // Called by a function in a landing page, in the popup window. The
97694             // window closes itself.
97695
97696
97697             window.authComplete = function (token) {
97698               var oauth_token = ohauth_1.stringQs(token.split('?')[1]);
97699               get_access_token(oauth_token.oauth_token);
97700               delete window.authComplete;
97701             }; // ## Getting an request token
97702             //
97703             // At this point we have an `oauth_token`, brought in from a function
97704             // call on a landing page popup.
97705
97706
97707             function get_access_token(oauth_token) {
97708               var url = o.url + '/oauth/access_token',
97709                   params = timenonce(getAuth(o)),
97710                   request_token_secret = token('oauth_request_token_secret');
97711               params.oauth_token = oauth_token;
97712               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
97713               //
97714               // The final token required for authentication. At this point
97715               // we have a `request token secret`
97716
97717               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
97718               o.loading();
97719             }
97720
97721             function accessTokenDone(err, xhr) {
97722               o.done();
97723               if (err) return callback(err);
97724               var access_token = ohauth_1.stringQs(xhr.response);
97725               token('oauth_token', access_token.oauth_token);
97726               token('oauth_token_secret', access_token.oauth_token_secret);
97727               callback(null, oauth);
97728             }
97729           };
97730
97731           oauth.bringPopupWindowToFront = function () {
97732             var brougtPopupToFront = false;
97733
97734             try {
97735               // This may cause a cross-origin error:
97736               // `DOMException: Blocked a frame with origin "..." from accessing a cross-origin frame.`
97737               if (oauth.popupWindow && !oauth.popupWindow.closed) {
97738                 oauth.popupWindow.focus();
97739                 brougtPopupToFront = true;
97740               }
97741             } catch (err) {// Bringing popup window to front failed (probably because of the cross-origin error mentioned above)
97742             }
97743
97744             return brougtPopupToFront;
97745           };
97746
97747           oauth.bootstrapToken = function (oauth_token, callback) {
97748             // ## Getting an request token
97749             // At this point we have an `oauth_token`, brought in from a function
97750             // call on a landing page popup.
97751             function get_access_token(oauth_token) {
97752               var url = o.url + '/oauth/access_token',
97753                   params = timenonce(getAuth(o)),
97754                   request_token_secret = token('oauth_request_token_secret');
97755               params.oauth_token = oauth_token;
97756               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
97757               // The final token required for authentication. At this point
97758               // we have a `request token secret`
97759
97760               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
97761               o.loading();
97762             }
97763
97764             function accessTokenDone(err, xhr) {
97765               o.done();
97766               if (err) return callback(err);
97767               var access_token = ohauth_1.stringQs(xhr.response);
97768               token('oauth_token', access_token.oauth_token);
97769               token('oauth_token_secret', access_token.oauth_token_secret);
97770               callback(null, oauth);
97771             }
97772
97773             get_access_token(oauth_token);
97774           }; // # xhr
97775           //
97776           // A single XMLHttpRequest wrapper that does authenticated calls if the
97777           // user has logged in.
97778
97779
97780           oauth.xhr = function (options, callback) {
97781             if (!oauth.authenticated()) {
97782               if (o.auto) {
97783                 return oauth.authenticate(run);
97784               } else {
97785                 callback('not authenticated', null);
97786                 return;
97787               }
97788             } else {
97789               return run();
97790             }
97791
97792             function run() {
97793               var params = timenonce(getAuth(o)),
97794                   oauth_token_secret = token('oauth_token_secret'),
97795                   url = options.prefix !== false ? o.url + options.path : options.path,
97796                   url_parts = url.replace(/#.*$/, '').split('?', 2),
97797                   base_url = url_parts[0],
97798                   query = url_parts.length === 2 ? url_parts[1] : ''; // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
97799
97800               if ((!options.options || !options.options.header || options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') && options.content) {
97801                 params = immutable(params, ohauth_1.stringQs(options.content));
97802               }
97803
97804               params.oauth_token = token('oauth_token');
97805               params.oauth_signature = ohauth_1.signature(o.oauth_secret, oauth_token_secret, ohauth_1.baseString(options.method, base_url, immutable(params, ohauth_1.stringQs(query))));
97806               return ohauth_1.xhr(options.method, url, params, options.content, options.options, done);
97807             }
97808
97809             function done(err, xhr) {
97810               if (err) return callback(err);else if (xhr.responseXML) return callback(err, xhr.responseXML);else return callback(err, xhr.response);
97811             }
97812           }; // pre-authorize this object, if we can just get a token and token_secret
97813           // from the start
97814
97815
97816           oauth.preauth = function (c) {
97817             if (!c) return;
97818             if (c.oauth_token) token('oauth_token', c.oauth_token);
97819             if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
97820             return oauth;
97821           };
97822
97823           oauth.options = function (_) {
97824             if (!arguments.length) return o;
97825             o = _;
97826             o.url = o.url || 'https://www.openstreetmap.org';
97827             o.landing = o.landing || 'land.html';
97828             o.singlepage = o.singlepage || false; // Optional loading and loading-done functions for nice UI feedback.
97829             // by default, no-ops
97830
97831             o.loading = o.loading || function () {};
97832
97833             o.done = o.done || function () {};
97834
97835             return oauth.preauth(o);
97836           }; // 'stamp' an authentication object from `getAuth()`
97837           // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
97838           // and timestamp
97839
97840
97841           function timenonce(o) {
97842             o.oauth_timestamp = ohauth_1.timestamp();
97843             o.oauth_nonce = ohauth_1.nonce();
97844             return o;
97845           } // get/set tokens. These are prefixed with the base URL so that `osm-auth`
97846           // can be used with multiple APIs and the keys in `localStorage`
97847           // will not clash
97848
97849
97850           var token;
97851
97852           if (store_legacy.enabled) {
97853             token = function token(x, y) {
97854               if (arguments.length === 1) return store_legacy.get(o.url + x);else if (arguments.length === 2) return store_legacy.set(o.url + x, y);
97855             };
97856           } else {
97857             var storage = {};
97858
97859             token = function token(x, y) {
97860               if (arguments.length === 1) return storage[o.url + x];else if (arguments.length === 2) return storage[o.url + x] = y;
97861             };
97862           } // Get an authentication object. If you just add and remove properties
97863           // from a single object, you'll need to use `delete` to make sure that
97864           // it doesn't contain undesired properties for authentication
97865
97866
97867           function getAuth(o) {
97868             return {
97869               oauth_consumer_key: o.oauth_consumer_key,
97870               oauth_signature_method: 'HMAC-SHA1'
97871             };
97872           } // potentially pre-authorize
97873
97874
97875           oauth.options(o);
97876           return oauth;
97877         };
97878
97879         var tiler$2 = utilTiler();
97880         var dispatch$2 = dispatch$8('apiStatusChange', 'authLoading', 'authDone', 'change', 'loading', 'loaded', 'loadedNotes');
97881         var urlroot = 'https://www.openstreetmap.org';
97882         var oauth = osmAuth({
97883           url: urlroot,
97884           oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
97885           oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
97886           loading: authLoading,
97887           done: authDone
97888         }); // hardcode default block of Google Maps
97889
97890         var _imageryBlocklists = [/.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/];
97891         var _tileCache = {
97892           toLoad: {},
97893           loaded: {},
97894           inflight: {},
97895           seen: {},
97896           rtree: new RBush()
97897         };
97898         var _noteCache = {
97899           toLoad: {},
97900           loaded: {},
97901           inflight: {},
97902           inflightPost: {},
97903           note: {},
97904           closed: {},
97905           rtree: new RBush()
97906         };
97907         var _userCache = {
97908           toLoad: {},
97909           user: {}
97910         };
97911
97912         var _cachedApiStatus;
97913
97914         var _changeset = {};
97915
97916         var _deferred = new Set();
97917
97918         var _connectionID = 1;
97919         var _tileZoom = 16;
97920         var _noteZoom = 12;
97921
97922         var _rateLimitError;
97923
97924         var _userChangesets;
97925
97926         var _userDetails;
97927
97928         var _off; // set a default but also load this from the API status
97929
97930
97931         var _maxWayNodes = 2000;
97932
97933         function authLoading() {
97934           dispatch$2.call('authLoading');
97935         }
97936
97937         function authDone() {
97938           dispatch$2.call('authDone');
97939         }
97940
97941         function abortRequest$2(controllerOrXHR) {
97942           if (controllerOrXHR) {
97943             controllerOrXHR.abort();
97944           }
97945         }
97946
97947         function hasInflightRequests(cache) {
97948           return Object.keys(cache.inflight).length;
97949         }
97950
97951         function abortUnwantedRequests(cache, visibleTiles) {
97952           Object.keys(cache.inflight).forEach(function (k) {
97953             if (cache.toLoad[k]) return;
97954             if (visibleTiles.find(function (tile) {
97955               return k === tile.id;
97956             })) return;
97957             abortRequest$2(cache.inflight[k]);
97958             delete cache.inflight[k];
97959           });
97960         }
97961
97962         function getLoc(attrs) {
97963           var lon = attrs.lon && attrs.lon.value;
97964           var lat = attrs.lat && attrs.lat.value;
97965           return [parseFloat(lon), parseFloat(lat)];
97966         }
97967
97968         function getNodes(obj) {
97969           var elems = obj.getElementsByTagName('nd');
97970           var nodes = new Array(elems.length);
97971
97972           for (var i = 0, l = elems.length; i < l; i++) {
97973             nodes[i] = 'n' + elems[i].attributes.ref.value;
97974           }
97975
97976           return nodes;
97977         }
97978
97979         function getNodesJSON(obj) {
97980           var elems = obj.nodes;
97981           var nodes = new Array(elems.length);
97982
97983           for (var i = 0, l = elems.length; i < l; i++) {
97984             nodes[i] = 'n' + elems[i];
97985           }
97986
97987           return nodes;
97988         }
97989
97990         function getTags(obj) {
97991           var elems = obj.getElementsByTagName('tag');
97992           var tags = {};
97993
97994           for (var i = 0, l = elems.length; i < l; i++) {
97995             var attrs = elems[i].attributes;
97996             tags[attrs.k.value] = attrs.v.value;
97997           }
97998
97999           return tags;
98000         }
98001
98002         function getMembers(obj) {
98003           var elems = obj.getElementsByTagName('member');
98004           var members = new Array(elems.length);
98005
98006           for (var i = 0, l = elems.length; i < l; i++) {
98007             var attrs = elems[i].attributes;
98008             members[i] = {
98009               id: attrs.type.value[0] + attrs.ref.value,
98010               type: attrs.type.value,
98011               role: attrs.role.value
98012             };
98013           }
98014
98015           return members;
98016         }
98017
98018         function getMembersJSON(obj) {
98019           var elems = obj.members;
98020           var members = new Array(elems.length);
98021
98022           for (var i = 0, l = elems.length; i < l; i++) {
98023             var attrs = elems[i];
98024             members[i] = {
98025               id: attrs.type[0] + attrs.ref,
98026               type: attrs.type,
98027               role: attrs.role
98028             };
98029           }
98030
98031           return members;
98032         }
98033
98034         function getVisible(attrs) {
98035           return !attrs.visible || attrs.visible.value !== 'false';
98036         }
98037
98038         function parseComments(comments) {
98039           var parsedComments = []; // for each comment
98040
98041           for (var i = 0; i < comments.length; i++) {
98042             var comment = comments[i];
98043
98044             if (comment.nodeName === 'comment') {
98045               var childNodes = comment.childNodes;
98046               var parsedComment = {};
98047
98048               for (var j = 0; j < childNodes.length; j++) {
98049                 var node = childNodes[j];
98050                 var nodeName = node.nodeName;
98051                 if (nodeName === '#text') continue;
98052                 parsedComment[nodeName] = node.textContent;
98053
98054                 if (nodeName === 'uid') {
98055                   var uid = node.textContent;
98056
98057                   if (uid && !_userCache.user[uid]) {
98058                     _userCache.toLoad[uid] = true;
98059                   }
98060                 }
98061               }
98062
98063               if (parsedComment) {
98064                 parsedComments.push(parsedComment);
98065               }
98066             }
98067           }
98068
98069           return parsedComments;
98070         }
98071
98072         function encodeNoteRtree(note) {
98073           return {
98074             minX: note.loc[0],
98075             minY: note.loc[1],
98076             maxX: note.loc[0],
98077             maxY: note.loc[1],
98078             data: note
98079           };
98080         }
98081
98082         var jsonparsers = {
98083           node: function nodeData(obj, uid) {
98084             return new osmNode({
98085               id: uid,
98086               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
98087               version: obj.version && obj.version.toString(),
98088               changeset: obj.changeset && obj.changeset.toString(),
98089               timestamp: obj.timestamp,
98090               user: obj.user,
98091               uid: obj.uid && obj.uid.toString(),
98092               loc: [parseFloat(obj.lon), parseFloat(obj.lat)],
98093               tags: obj.tags
98094             });
98095           },
98096           way: function wayData(obj, uid) {
98097             return new osmWay({
98098               id: uid,
98099               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
98100               version: obj.version && obj.version.toString(),
98101               changeset: obj.changeset && obj.changeset.toString(),
98102               timestamp: obj.timestamp,
98103               user: obj.user,
98104               uid: obj.uid && obj.uid.toString(),
98105               tags: obj.tags,
98106               nodes: getNodesJSON(obj)
98107             });
98108           },
98109           relation: function relationData(obj, uid) {
98110             return new osmRelation({
98111               id: uid,
98112               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
98113               version: obj.version && obj.version.toString(),
98114               changeset: obj.changeset && obj.changeset.toString(),
98115               timestamp: obj.timestamp,
98116               user: obj.user,
98117               uid: obj.uid && obj.uid.toString(),
98118               tags: obj.tags,
98119               members: getMembersJSON(obj)
98120             });
98121           },
98122           user: function parseUser(obj, uid) {
98123             return {
98124               id: uid,
98125               display_name: obj.display_name,
98126               account_created: obj.account_created,
98127               image_url: obj.img && obj.img.href,
98128               changesets_count: obj.changesets && obj.changesets.count && obj.changesets.count.toString() || '0',
98129               active_blocks: obj.blocks && obj.blocks.received && obj.blocks.received.active && obj.blocks.received.active.toString() || '0'
98130             };
98131           }
98132         };
98133
98134         function parseJSON(payload, callback, options) {
98135           options = Object.assign({
98136             skipSeen: true
98137           }, options);
98138
98139           if (!payload) {
98140             return callback({
98141               message: 'No JSON',
98142               status: -1
98143             });
98144           }
98145
98146           var json = payload;
98147           if (_typeof(json) !== 'object') json = JSON.parse(payload);
98148           if (!json.elements) return callback({
98149             message: 'No JSON',
98150             status: -1
98151           });
98152           var children = json.elements;
98153           var handle = window.requestIdleCallback(function () {
98154             _deferred["delete"](handle);
98155
98156             var results = [];
98157             var result;
98158
98159             for (var i = 0; i < children.length; i++) {
98160               result = parseChild(children[i]);
98161               if (result) results.push(result);
98162             }
98163
98164             callback(null, results);
98165           });
98166
98167           _deferred.add(handle);
98168
98169           function parseChild(child) {
98170             var parser = jsonparsers[child.type];
98171             if (!parser) return null;
98172             var uid;
98173             uid = osmEntity.id.fromOSM(child.type, child.id);
98174
98175             if (options.skipSeen) {
98176               if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
98177
98178               _tileCache.seen[uid] = true;
98179             }
98180
98181             return parser(child, uid);
98182           }
98183         }
98184
98185         function parseUserJSON(payload, callback, options) {
98186           options = Object.assign({
98187             skipSeen: true
98188           }, options);
98189
98190           if (!payload) {
98191             return callback({
98192               message: 'No JSON',
98193               status: -1
98194             });
98195           }
98196
98197           var json = payload;
98198           if (_typeof(json) !== 'object') json = JSON.parse(payload);
98199           if (!json.users && !json.user) return callback({
98200             message: 'No JSON',
98201             status: -1
98202           });
98203           var objs = json.users || [json];
98204           var handle = window.requestIdleCallback(function () {
98205             _deferred["delete"](handle);
98206
98207             var results = [];
98208             var result;
98209
98210             for (var i = 0; i < objs.length; i++) {
98211               result = parseObj(objs[i]);
98212               if (result) results.push(result);
98213             }
98214
98215             callback(null, results);
98216           });
98217
98218           _deferred.add(handle);
98219
98220           function parseObj(obj) {
98221             var uid = obj.user.id && obj.user.id.toString();
98222
98223             if (options.skipSeen && _userCache.user[uid]) {
98224               delete _userCache.toLoad[uid];
98225               return null;
98226             }
98227
98228             var user = jsonparsers.user(obj.user, uid);
98229             _userCache.user[uid] = user;
98230             delete _userCache.toLoad[uid];
98231             return user;
98232           }
98233         }
98234
98235         var parsers = {
98236           node: function nodeData(obj, uid) {
98237             var attrs = obj.attributes;
98238             return new osmNode({
98239               id: uid,
98240               visible: getVisible(attrs),
98241               version: attrs.version.value,
98242               changeset: attrs.changeset && attrs.changeset.value,
98243               timestamp: attrs.timestamp && attrs.timestamp.value,
98244               user: attrs.user && attrs.user.value,
98245               uid: attrs.uid && attrs.uid.value,
98246               loc: getLoc(attrs),
98247               tags: getTags(obj)
98248             });
98249           },
98250           way: function wayData(obj, uid) {
98251             var attrs = obj.attributes;
98252             return new osmWay({
98253               id: uid,
98254               visible: getVisible(attrs),
98255               version: attrs.version.value,
98256               changeset: attrs.changeset && attrs.changeset.value,
98257               timestamp: attrs.timestamp && attrs.timestamp.value,
98258               user: attrs.user && attrs.user.value,
98259               uid: attrs.uid && attrs.uid.value,
98260               tags: getTags(obj),
98261               nodes: getNodes(obj)
98262             });
98263           },
98264           relation: function relationData(obj, uid) {
98265             var attrs = obj.attributes;
98266             return new osmRelation({
98267               id: uid,
98268               visible: getVisible(attrs),
98269               version: attrs.version.value,
98270               changeset: attrs.changeset && attrs.changeset.value,
98271               timestamp: attrs.timestamp && attrs.timestamp.value,
98272               user: attrs.user && attrs.user.value,
98273               uid: attrs.uid && attrs.uid.value,
98274               tags: getTags(obj),
98275               members: getMembers(obj)
98276             });
98277           },
98278           note: function parseNote(obj, uid) {
98279             var attrs = obj.attributes;
98280             var childNodes = obj.childNodes;
98281             var props = {};
98282             props.id = uid;
98283             props.loc = getLoc(attrs); // if notes are coincident, move them apart slightly
98284
98285             var coincident = false;
98286             var epsilon = 0.00001;
98287
98288             do {
98289               if (coincident) {
98290                 props.loc = geoVecAdd(props.loc, [epsilon, epsilon]);
98291               }
98292
98293               var bbox = geoExtent(props.loc).bbox();
98294               coincident = _noteCache.rtree.search(bbox).length;
98295             } while (coincident); // parse note contents
98296
98297
98298             for (var i = 0; i < childNodes.length; i++) {
98299               var node = childNodes[i];
98300               var nodeName = node.nodeName;
98301               if (nodeName === '#text') continue; // if the element is comments, parse the comments
98302
98303               if (nodeName === 'comments') {
98304                 props[nodeName] = parseComments(node.childNodes);
98305               } else {
98306                 props[nodeName] = node.textContent;
98307               }
98308             }
98309
98310             var note = new osmNote(props);
98311             var item = encodeNoteRtree(note);
98312             _noteCache.note[note.id] = note;
98313
98314             _noteCache.rtree.insert(item);
98315
98316             return note;
98317           },
98318           user: function parseUser(obj, uid) {
98319             var attrs = obj.attributes;
98320             var user = {
98321               id: uid,
98322               display_name: attrs.display_name && attrs.display_name.value,
98323               account_created: attrs.account_created && attrs.account_created.value,
98324               changesets_count: '0',
98325               active_blocks: '0'
98326             };
98327             var img = obj.getElementsByTagName('img');
98328
98329             if (img && img[0] && img[0].getAttribute('href')) {
98330               user.image_url = img[0].getAttribute('href');
98331             }
98332
98333             var changesets = obj.getElementsByTagName('changesets');
98334
98335             if (changesets && changesets[0] && changesets[0].getAttribute('count')) {
98336               user.changesets_count = changesets[0].getAttribute('count');
98337             }
98338
98339             var blocks = obj.getElementsByTagName('blocks');
98340
98341             if (blocks && blocks[0]) {
98342               var received = blocks[0].getElementsByTagName('received');
98343
98344               if (received && received[0] && received[0].getAttribute('active')) {
98345                 user.active_blocks = received[0].getAttribute('active');
98346               }
98347             }
98348
98349             _userCache.user[uid] = user;
98350             delete _userCache.toLoad[uid];
98351             return user;
98352           }
98353         };
98354
98355         function parseXML(xml, callback, options) {
98356           options = Object.assign({
98357             skipSeen: true
98358           }, options);
98359
98360           if (!xml || !xml.childNodes) {
98361             return callback({
98362               message: 'No XML',
98363               status: -1
98364             });
98365           }
98366
98367           var root = xml.childNodes[0];
98368           var children = root.childNodes;
98369           var handle = window.requestIdleCallback(function () {
98370             _deferred["delete"](handle);
98371
98372             var results = [];
98373             var result;
98374
98375             for (var i = 0; i < children.length; i++) {
98376               result = parseChild(children[i]);
98377               if (result) results.push(result);
98378             }
98379
98380             callback(null, results);
98381           });
98382
98383           _deferred.add(handle);
98384
98385           function parseChild(child) {
98386             var parser = parsers[child.nodeName];
98387             if (!parser) return null;
98388             var uid;
98389
98390             if (child.nodeName === 'user') {
98391               uid = child.attributes.id.value;
98392
98393               if (options.skipSeen && _userCache.user[uid]) {
98394                 delete _userCache.toLoad[uid];
98395                 return null;
98396               }
98397             } else if (child.nodeName === 'note') {
98398               uid = child.getElementsByTagName('id')[0].textContent;
98399             } else {
98400               uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
98401
98402               if (options.skipSeen) {
98403                 if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
98404
98405                 _tileCache.seen[uid] = true;
98406               }
98407             }
98408
98409             return parser(child, uid);
98410           }
98411         } // replace or remove note from rtree
98412
98413
98414         function updateRtree(item, replace) {
98415           _noteCache.rtree.remove(item, function isEql(a, b) {
98416             return a.data.id === b.data.id;
98417           });
98418
98419           if (replace) {
98420             _noteCache.rtree.insert(item);
98421           }
98422         }
98423
98424         function wrapcb(thisArg, callback, cid) {
98425           return function (err, result) {
98426             if (err) {
98427               // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
98428               if (err.status === 400 || err.status === 401 || err.status === 403) {
98429                 thisArg.logout();
98430               }
98431
98432               return callback.call(thisArg, err);
98433             } else if (thisArg.getConnectionId() !== cid) {
98434               return callback.call(thisArg, {
98435                 message: 'Connection Switched',
98436                 status: -1
98437               });
98438             } else {
98439               return callback.call(thisArg, err, result);
98440             }
98441           };
98442         }
98443
98444         var serviceOsm = {
98445           init: function init() {
98446             utilRebind(this, dispatch$2, 'on');
98447           },
98448           reset: function reset() {
98449             Array.from(_deferred).forEach(function (handle) {
98450               window.cancelIdleCallback(handle);
98451
98452               _deferred["delete"](handle);
98453             });
98454             _connectionID++;
98455             _userChangesets = undefined;
98456             _userDetails = undefined;
98457             _rateLimitError = undefined;
98458             Object.values(_tileCache.inflight).forEach(abortRequest$2);
98459             Object.values(_noteCache.inflight).forEach(abortRequest$2);
98460             Object.values(_noteCache.inflightPost).forEach(abortRequest$2);
98461             if (_changeset.inflight) abortRequest$2(_changeset.inflight);
98462             _tileCache = {
98463               toLoad: {},
98464               loaded: {},
98465               inflight: {},
98466               seen: {},
98467               rtree: new RBush()
98468             };
98469             _noteCache = {
98470               toLoad: {},
98471               loaded: {},
98472               inflight: {},
98473               inflightPost: {},
98474               note: {},
98475               closed: {},
98476               rtree: new RBush()
98477             };
98478             _userCache = {
98479               toLoad: {},
98480               user: {}
98481             };
98482             _cachedApiStatus = undefined;
98483             _changeset = {};
98484             return this;
98485           },
98486           getConnectionId: function getConnectionId() {
98487             return _connectionID;
98488           },
98489           changesetURL: function changesetURL(changesetID) {
98490             return urlroot + '/changeset/' + changesetID;
98491           },
98492           changesetsURL: function changesetsURL(center, zoom) {
98493             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
98494             return urlroot + '/history#map=' + Math.floor(zoom) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
98495           },
98496           entityURL: function entityURL(entity) {
98497             return urlroot + '/' + entity.type + '/' + entity.osmId();
98498           },
98499           historyURL: function historyURL(entity) {
98500             return urlroot + '/' + entity.type + '/' + entity.osmId() + '/history';
98501           },
98502           userURL: function userURL(username) {
98503             return urlroot + '/user/' + username;
98504           },
98505           noteURL: function noteURL(note) {
98506             return urlroot + '/note/' + note.id;
98507           },
98508           noteReportURL: function noteReportURL(note) {
98509             return urlroot + '/reports/new?reportable_type=Note&reportable_id=' + note.id;
98510           },
98511           // Generic method to load data from the OSM API
98512           // Can handle either auth or unauth calls.
98513           loadFromAPI: function loadFromAPI(path, callback, options) {
98514             options = Object.assign({
98515               skipSeen: true
98516             }, options);
98517             var that = this;
98518             var cid = _connectionID;
98519
98520             function done(err, payload) {
98521               if (that.getConnectionId() !== cid) {
98522                 if (callback) callback({
98523                   message: 'Connection Switched',
98524                   status: -1
98525                 });
98526                 return;
98527               }
98528
98529               var isAuthenticated = that.authenticated(); // 400 Bad Request, 401 Unauthorized, 403 Forbidden
98530               // Logout and retry the request..
98531
98532               if (isAuthenticated && err && err.status && (err.status === 400 || err.status === 401 || err.status === 403)) {
98533                 that.logout();
98534                 that.loadFromAPI(path, callback, options); // else, no retry..
98535               } else {
98536                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
98537                 // Set the rateLimitError flag and trigger a warning..
98538                 if (!isAuthenticated && !_rateLimitError && err && err.status && (err.status === 509 || err.status === 429)) {
98539                   _rateLimitError = err;
98540                   dispatch$2.call('change');
98541                   that.reloadApiStatus();
98542                 } else if (err && _cachedApiStatus === 'online' || !err && _cachedApiStatus !== 'online') {
98543                   // If the response's error state doesn't match the status,
98544                   // it's likely we lost or gained the connection so reload the status
98545                   that.reloadApiStatus();
98546                 }
98547
98548                 if (callback) {
98549                   if (err) {
98550                     return callback(err);
98551                   } else {
98552                     if (path.indexOf('.json') !== -1) {
98553                       return parseJSON(payload, callback, options);
98554                     } else {
98555                       return parseXML(payload, callback, options);
98556                     }
98557                   }
98558                 }
98559               }
98560             }
98561
98562             if (this.authenticated()) {
98563               return oauth.xhr({
98564                 method: 'GET',
98565                 path: path
98566               }, done);
98567             } else {
98568               var url = urlroot + path;
98569               var controller = new AbortController();
98570               var fn;
98571
98572               if (path.indexOf('.json') !== -1) {
98573                 fn = d3_json;
98574               } else {
98575                 fn = d3_xml;
98576               }
98577
98578               fn(url, {
98579                 signal: controller.signal
98580               }).then(function (data) {
98581                 done(null, data);
98582               })["catch"](function (err) {
98583                 if (err.name === 'AbortError') return; // d3-fetch includes status in the error message,
98584                 // but we can't access the response itself
98585                 // https://github.com/d3/d3-fetch/issues/27
98586
98587                 var match = err.message.match(/^\d{3}/);
98588
98589                 if (match) {
98590                   done({
98591                     status: +match[0],
98592                     statusText: err.message
98593                   });
98594                 } else {
98595                   done(err.message);
98596                 }
98597               });
98598               return controller;
98599             }
98600           },
98601           // Load a single entity by id (ways and relations use the `/full` call to include
98602           // nodes and members). Parent relations are not included, see `loadEntityRelations`.
98603           // GET /api/0.6/node/#id
98604           // GET /api/0.6/[way|relation]/#id/full
98605           loadEntity: function loadEntity(id, callback) {
98606             var type = osmEntity.id.type(id);
98607             var osmID = osmEntity.id.toOSM(id);
98608             var options = {
98609               skipSeen: false
98610             };
98611             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : '') + '.json', function (err, entities) {
98612               if (callback) callback(err, {
98613                 data: entities
98614               });
98615             }, options);
98616           },
98617           // Load a single entity with a specific version
98618           // GET /api/0.6/[node|way|relation]/#id/#version
98619           loadEntityVersion: function loadEntityVersion(id, version, callback) {
98620             var type = osmEntity.id.type(id);
98621             var osmID = osmEntity.id.toOSM(id);
98622             var options = {
98623               skipSeen: false
98624             };
98625             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/' + version + '.json', function (err, entities) {
98626               if (callback) callback(err, {
98627                 data: entities
98628               });
98629             }, options);
98630           },
98631           // Load the relations of a single entity with the given.
98632           // GET /api/0.6/[node|way|relation]/#id/relations
98633           loadEntityRelations: function loadEntityRelations(id, callback) {
98634             var type = osmEntity.id.type(id);
98635             var osmID = osmEntity.id.toOSM(id);
98636             var options = {
98637               skipSeen: false
98638             };
98639             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/relations.json', function (err, entities) {
98640               if (callback) callback(err, {
98641                 data: entities
98642               });
98643             }, options);
98644           },
98645           // Load multiple entities in chunks
98646           // (note: callback may be called multiple times)
98647           // Unlike `loadEntity`, child nodes and members are not fetched
98648           // GET /api/0.6/[nodes|ways|relations]?#parameters
98649           loadMultiple: function loadMultiple(ids, callback) {
98650             var that = this;
98651             var groups = utilArrayGroupBy(utilArrayUniq(ids), osmEntity.id.type);
98652             Object.keys(groups).forEach(function (k) {
98653               var type = k + 's'; // nodes, ways, relations
98654
98655               var osmIDs = groups[k].map(function (id) {
98656                 return osmEntity.id.toOSM(id);
98657               });
98658               var options = {
98659                 skipSeen: false
98660               };
98661               utilArrayChunk(osmIDs, 150).forEach(function (arr) {
98662                 that.loadFromAPI('/api/0.6/' + type + '.json?' + type + '=' + arr.join(), function (err, entities) {
98663                   if (callback) callback(err, {
98664                     data: entities
98665                   });
98666                 }, options);
98667               });
98668             });
98669           },
98670           // Create, upload, and close a changeset
98671           // PUT /api/0.6/changeset/create
98672           // POST /api/0.6/changeset/#id/upload
98673           // PUT /api/0.6/changeset/#id/close
98674           putChangeset: function putChangeset(changeset, changes, callback) {
98675             var cid = _connectionID;
98676
98677             if (_changeset.inflight) {
98678               return callback({
98679                 message: 'Changeset already inflight',
98680                 status: -2
98681               }, changeset);
98682             } else if (_changeset.open) {
98683               // reuse existing open changeset..
98684               return createdChangeset.call(this, null, _changeset.open);
98685             } else {
98686               // Open a new changeset..
98687               var options = {
98688                 method: 'PUT',
98689                 path: '/api/0.6/changeset/create',
98690                 options: {
98691                   header: {
98692                     'Content-Type': 'text/xml'
98693                   }
98694                 },
98695                 content: JXON.stringify(changeset.asJXON())
98696               };
98697               _changeset.inflight = oauth.xhr(options, wrapcb(this, createdChangeset, cid));
98698             }
98699
98700             function createdChangeset(err, changesetID) {
98701               _changeset.inflight = null;
98702
98703               if (err) {
98704                 return callback(err, changeset);
98705               }
98706
98707               _changeset.open = changesetID;
98708               changeset = changeset.update({
98709                 id: changesetID
98710               }); // Upload the changeset..
98711
98712               var options = {
98713                 method: 'POST',
98714                 path: '/api/0.6/changeset/' + changesetID + '/upload',
98715                 options: {
98716                   header: {
98717                     'Content-Type': 'text/xml'
98718                   }
98719                 },
98720                 content: JXON.stringify(changeset.osmChangeJXON(changes))
98721               };
98722               _changeset.inflight = oauth.xhr(options, wrapcb(this, uploadedChangeset, cid));
98723             }
98724
98725             function uploadedChangeset(err) {
98726               _changeset.inflight = null;
98727               if (err) return callback(err, changeset); // Upload was successful, safe to call the callback.
98728               // Add delay to allow for postgres replication #1646 #2678
98729
98730               window.setTimeout(function () {
98731                 callback(null, changeset);
98732               }, 2500);
98733               _changeset.open = null; // At this point, we don't really care if the connection was switched..
98734               // Only try to close the changeset if we're still talking to the same server.
98735
98736               if (this.getConnectionId() === cid) {
98737                 // Still attempt to close changeset, but ignore response because #2667
98738                 oauth.xhr({
98739                   method: 'PUT',
98740                   path: '/api/0.6/changeset/' + changeset.id + '/close',
98741                   options: {
98742                     header: {
98743                       'Content-Type': 'text/xml'
98744                     }
98745                   }
98746                 }, function () {
98747                   return true;
98748                 });
98749               }
98750             }
98751           },
98752           // Load multiple users in chunks
98753           // (note: callback may be called multiple times)
98754           // GET /api/0.6/users?users=#id1,#id2,...,#idn
98755           loadUsers: function loadUsers(uids, callback) {
98756             var toLoad = [];
98757             var cached = [];
98758             utilArrayUniq(uids).forEach(function (uid) {
98759               if (_userCache.user[uid]) {
98760                 delete _userCache.toLoad[uid];
98761                 cached.push(_userCache.user[uid]);
98762               } else {
98763                 toLoad.push(uid);
98764               }
98765             });
98766
98767             if (cached.length || !this.authenticated()) {
98768               callback(undefined, cached);
98769               if (!this.authenticated()) return; // require auth
98770             }
98771
98772             utilArrayChunk(toLoad, 150).forEach(function (arr) {
98773               oauth.xhr({
98774                 method: 'GET',
98775                 path: '/api/0.6/users.json?users=' + arr.join()
98776               }, wrapcb(this, done, _connectionID));
98777             }.bind(this));
98778
98779             function done(err, payload) {
98780               if (err) return callback(err);
98781               var options = {
98782                 skipSeen: true
98783               };
98784               return parseUserJSON(payload, function (err, results) {
98785                 if (err) return callback(err);
98786                 return callback(undefined, results);
98787               }, options);
98788             }
98789           },
98790           // Load a given user by id
98791           // GET /api/0.6/user/#id
98792           loadUser: function loadUser(uid, callback) {
98793             if (_userCache.user[uid] || !this.authenticated()) {
98794               // require auth
98795               delete _userCache.toLoad[uid];
98796               return callback(undefined, _userCache.user[uid]);
98797             }
98798
98799             oauth.xhr({
98800               method: 'GET',
98801               path: '/api/0.6/user/' + uid + '.json'
98802             }, wrapcb(this, done, _connectionID));
98803
98804             function done(err, payload) {
98805               if (err) return callback(err);
98806               var options = {
98807                 skipSeen: true
98808               };
98809               return parseUserJSON(payload, function (err, results) {
98810                 if (err) return callback(err);
98811                 return callback(undefined, results[0]);
98812               }, options);
98813             }
98814           },
98815           // Load the details of the logged-in user
98816           // GET /api/0.6/user/details
98817           userDetails: function userDetails(callback) {
98818             if (_userDetails) {
98819               // retrieve cached
98820               return callback(undefined, _userDetails);
98821             }
98822
98823             oauth.xhr({
98824               method: 'GET',
98825               path: '/api/0.6/user/details.json'
98826             }, wrapcb(this, done, _connectionID));
98827
98828             function done(err, payload) {
98829               if (err) return callback(err);
98830               var options = {
98831                 skipSeen: false
98832               };
98833               return parseUserJSON(payload, function (err, results) {
98834                 if (err) return callback(err);
98835                 _userDetails = results[0];
98836                 return callback(undefined, _userDetails);
98837               }, options);
98838             }
98839           },
98840           // Load previous changesets for the logged in user
98841           // GET /api/0.6/changesets?user=#id
98842           userChangesets: function userChangesets(callback) {
98843             if (_userChangesets) {
98844               // retrieve cached
98845               return callback(undefined, _userChangesets);
98846             }
98847
98848             this.userDetails(wrapcb(this, gotDetails, _connectionID));
98849
98850             function gotDetails(err, user) {
98851               if (err) {
98852                 return callback(err);
98853               }
98854
98855               oauth.xhr({
98856                 method: 'GET',
98857                 path: '/api/0.6/changesets?user=' + user.id
98858               }, wrapcb(this, done, _connectionID));
98859             }
98860
98861             function done(err, xml) {
98862               if (err) {
98863                 return callback(err);
98864               }
98865
98866               _userChangesets = Array.prototype.map.call(xml.getElementsByTagName('changeset'), function (changeset) {
98867                 return {
98868                   tags: getTags(changeset)
98869                 };
98870               }).filter(function (changeset) {
98871                 var comment = changeset.tags.comment;
98872                 return comment && comment !== '';
98873               });
98874               return callback(undefined, _userChangesets);
98875             }
98876           },
98877           // Fetch the status of the OSM API
98878           // GET /api/capabilities
98879           status: function status(callback) {
98880             var url = urlroot + '/api/capabilities';
98881             var errback = wrapcb(this, done, _connectionID);
98882             d3_xml(url).then(function (data) {
98883               errback(null, data);
98884             })["catch"](function (err) {
98885               errback(err.message);
98886             });
98887
98888             function done(err, xml) {
98889               if (err) {
98890                 // the status is null if no response could be retrieved
98891                 return callback(err, null);
98892               } // update blocklists
98893
98894
98895               var elements = xml.getElementsByTagName('blacklist');
98896               var regexes = [];
98897
98898               for (var i = 0; i < elements.length; i++) {
98899                 var regexString = elements[i].getAttribute('regex'); // needs unencode?
98900
98901                 if (regexString) {
98902                   try {
98903                     var regex = new RegExp(regexString);
98904                     regexes.push(regex);
98905                   } catch (e) {
98906                     /* noop */
98907                   }
98908                 }
98909               }
98910
98911               if (regexes.length) {
98912                 _imageryBlocklists = regexes;
98913               }
98914
98915               if (_rateLimitError) {
98916                 return callback(_rateLimitError, 'rateLimited');
98917               } else {
98918                 var waynodes = xml.getElementsByTagName('waynodes');
98919                 var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute('maximum'), 10);
98920                 if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
98921                 var apiStatus = xml.getElementsByTagName('status');
98922                 var val = apiStatus[0].getAttribute('api');
98923                 return callback(undefined, val);
98924               }
98925             }
98926           },
98927           // Calls `status` and dispatches an `apiStatusChange` event if the returned
98928           // status differs from the cached status.
98929           reloadApiStatus: function reloadApiStatus() {
98930             // throttle to avoid unnecessary API calls
98931             if (!this.throttledReloadApiStatus) {
98932               var that = this;
98933               this.throttledReloadApiStatus = throttle(function () {
98934                 that.status(function (err, status) {
98935                   if (status !== _cachedApiStatus) {
98936                     _cachedApiStatus = status;
98937                     dispatch$2.call('apiStatusChange', that, err, status);
98938                   }
98939                 });
98940               }, 500);
98941             }
98942
98943             this.throttledReloadApiStatus();
98944           },
98945           // Returns the maximum number of nodes a single way can have
98946           maxWayNodes: function maxWayNodes() {
98947             return _maxWayNodes;
98948           },
98949           // Load data (entities) from the API in tiles
98950           // GET /api/0.6/map?bbox=
98951           loadTiles: function loadTiles(projection, callback) {
98952             if (_off) return; // determine the needed tiles to cover the view
98953
98954             var tiles = tiler$2.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection); // abort inflight requests that are no longer needed
98955
98956             var hadRequests = hasInflightRequests(_tileCache);
98957             abortUnwantedRequests(_tileCache, tiles);
98958
98959             if (hadRequests && !hasInflightRequests(_tileCache)) {
98960               dispatch$2.call('loaded'); // stop the spinner
98961             } // issue new requests..
98962
98963
98964             tiles.forEach(function (tile) {
98965               this.loadTile(tile, callback);
98966             }, this);
98967           },
98968           // Load a single data tile
98969           // GET /api/0.6/map?bbox=
98970           loadTile: function loadTile(tile, callback) {
98971             if (_off) return;
98972             if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
98973
98974             if (!hasInflightRequests(_tileCache)) {
98975               dispatch$2.call('loading'); // start the spinner
98976             }
98977
98978             var path = '/api/0.6/map.json?bbox=';
98979             var options = {
98980               skipSeen: true
98981             };
98982             _tileCache.inflight[tile.id] = this.loadFromAPI(path + tile.extent.toParam(), tileCallback, options);
98983
98984             function tileCallback(err, parsed) {
98985               delete _tileCache.inflight[tile.id];
98986
98987               if (!err) {
98988                 delete _tileCache.toLoad[tile.id];
98989                 _tileCache.loaded[tile.id] = true;
98990                 var bbox = tile.extent.bbox();
98991                 bbox.id = tile.id;
98992
98993                 _tileCache.rtree.insert(bbox);
98994               }
98995
98996               if (callback) {
98997                 callback(err, Object.assign({
98998                   data: parsed
98999                 }, tile));
99000               }
99001
99002               if (!hasInflightRequests(_tileCache)) {
99003                 dispatch$2.call('loaded'); // stop the spinner
99004               }
99005             }
99006           },
99007           isDataLoaded: function isDataLoaded(loc) {
99008             var bbox = {
99009               minX: loc[0],
99010               minY: loc[1],
99011               maxX: loc[0],
99012               maxY: loc[1]
99013             };
99014             return _tileCache.rtree.collides(bbox);
99015           },
99016           // load the tile that covers the given `loc`
99017           loadTileAtLoc: function loadTileAtLoc(loc, callback) {
99018             // Back off if the toLoad queue is filling up.. re #6417
99019             // (Currently `loadTileAtLoc` requests are considered low priority - used by operations to
99020             // let users safely edit geometries which extend to unloaded tiles.  We can drop some.)
99021             if (Object.keys(_tileCache.toLoad).length > 50) return;
99022             var k = geoZoomToScale(_tileZoom + 1);
99023             var offset = geoRawMercator().scale(k)(loc);
99024             var projection = geoRawMercator().transform({
99025               k: k,
99026               x: -offset[0],
99027               y: -offset[1]
99028             });
99029             var tiles = tiler$2.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection);
99030             tiles.forEach(function (tile) {
99031               if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
99032               _tileCache.toLoad[tile.id] = true;
99033               this.loadTile(tile, callback);
99034             }, this);
99035           },
99036           // Load notes from the API in tiles
99037           // GET /api/0.6/notes?bbox=
99038           loadNotes: function loadNotes(projection, noteOptions) {
99039             noteOptions = Object.assign({
99040               limit: 10000,
99041               closed: 7
99042             }, noteOptions);
99043             if (_off) return;
99044             var that = this;
99045             var path = '/api/0.6/notes?limit=' + noteOptions.limit + '&closed=' + noteOptions.closed + '&bbox=';
99046
99047             var throttleLoadUsers = throttle(function () {
99048               var uids = Object.keys(_userCache.toLoad);
99049               if (!uids.length) return;
99050               that.loadUsers(uids, function () {}); // eagerly load user details
99051             }, 750); // determine the needed tiles to cover the view
99052
99053
99054             var tiles = tiler$2.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection); // abort inflight requests that are no longer needed
99055
99056             abortUnwantedRequests(_noteCache, tiles); // issue new requests..
99057
99058             tiles.forEach(function (tile) {
99059               if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
99060               var options = {
99061                 skipSeen: false
99062               };
99063               _noteCache.inflight[tile.id] = that.loadFromAPI(path + tile.extent.toParam(), function (err) {
99064                 delete _noteCache.inflight[tile.id];
99065
99066                 if (!err) {
99067                   _noteCache.loaded[tile.id] = true;
99068                 }
99069
99070                 throttleLoadUsers();
99071                 dispatch$2.call('loadedNotes');
99072               }, options);
99073             });
99074           },
99075           // Create a note
99076           // POST /api/0.6/notes?params
99077           postNoteCreate: function postNoteCreate(note, callback) {
99078             if (!this.authenticated()) {
99079               return callback({
99080                 message: 'Not Authenticated',
99081                 status: -3
99082               }, note);
99083             }
99084
99085             if (_noteCache.inflightPost[note.id]) {
99086               return callback({
99087                 message: 'Note update already inflight',
99088                 status: -2
99089               }, note);
99090             }
99091
99092             if (!note.loc[0] || !note.loc[1] || !note.newComment) return; // location & description required
99093
99094             var comment = note.newComment;
99095
99096             if (note.newCategory && note.newCategory !== 'None') {
99097               comment += ' #' + note.newCategory;
99098             }
99099
99100             var path = '/api/0.6/notes?' + utilQsString({
99101               lon: note.loc[0],
99102               lat: note.loc[1],
99103               text: comment
99104             });
99105             _noteCache.inflightPost[note.id] = oauth.xhr({
99106               method: 'POST',
99107               path: path
99108             }, wrapcb(this, done, _connectionID));
99109
99110             function done(err, xml) {
99111               delete _noteCache.inflightPost[note.id];
99112
99113               if (err) {
99114                 return callback(err);
99115               } // we get the updated note back, remove from caches and reparse..
99116
99117
99118               this.removeNote(note);
99119               var options = {
99120                 skipSeen: false
99121               };
99122               return parseXML(xml, function (err, results) {
99123                 if (err) {
99124                   return callback(err);
99125                 } else {
99126                   return callback(undefined, results[0]);
99127                 }
99128               }, options);
99129             }
99130           },
99131           // Update a note
99132           // POST /api/0.6/notes/#id/comment?text=comment
99133           // POST /api/0.6/notes/#id/close?text=comment
99134           // POST /api/0.6/notes/#id/reopen?text=comment
99135           postNoteUpdate: function postNoteUpdate(note, newStatus, callback) {
99136             if (!this.authenticated()) {
99137               return callback({
99138                 message: 'Not Authenticated',
99139                 status: -3
99140               }, note);
99141             }
99142
99143             if (_noteCache.inflightPost[note.id]) {
99144               return callback({
99145                 message: 'Note update already inflight',
99146                 status: -2
99147               }, note);
99148             }
99149
99150             var action;
99151
99152             if (note.status !== 'closed' && newStatus === 'closed') {
99153               action = 'close';
99154             } else if (note.status !== 'open' && newStatus === 'open') {
99155               action = 'reopen';
99156             } else {
99157               action = 'comment';
99158               if (!note.newComment) return; // when commenting, comment required
99159             }
99160
99161             var path = '/api/0.6/notes/' + note.id + '/' + action;
99162
99163             if (note.newComment) {
99164               path += '?' + utilQsString({
99165                 text: note.newComment
99166               });
99167             }
99168
99169             _noteCache.inflightPost[note.id] = oauth.xhr({
99170               method: 'POST',
99171               path: path
99172             }, wrapcb(this, done, _connectionID));
99173
99174             function done(err, xml) {
99175               delete _noteCache.inflightPost[note.id];
99176
99177               if (err) {
99178                 return callback(err);
99179               } // we get the updated note back, remove from caches and reparse..
99180
99181
99182               this.removeNote(note); // update closed note cache - used to populate `closed:note` changeset tag
99183
99184               if (action === 'close') {
99185                 _noteCache.closed[note.id] = true;
99186               } else if (action === 'reopen') {
99187                 delete _noteCache.closed[note.id];
99188               }
99189
99190               var options = {
99191                 skipSeen: false
99192               };
99193               return parseXML(xml, function (err, results) {
99194                 if (err) {
99195                   return callback(err);
99196                 } else {
99197                   return callback(undefined, results[0]);
99198                 }
99199               }, options);
99200             }
99201           },
99202           "switch": function _switch(options) {
99203             urlroot = options.urlroot;
99204             oauth.options(Object.assign({
99205               url: urlroot,
99206               loading: authLoading,
99207               done: authDone
99208             }, options));
99209             this.reset();
99210             this.userChangesets(function () {}); // eagerly load user details/changesets
99211
99212             dispatch$2.call('change');
99213             return this;
99214           },
99215           toggle: function toggle(val) {
99216             _off = !val;
99217             return this;
99218           },
99219           isChangesetInflight: function isChangesetInflight() {
99220             return !!_changeset.inflight;
99221           },
99222           // get/set cached data
99223           // This is used to save/restore the state when entering/exiting the walkthrough
99224           // Also used for testing purposes.
99225           caches: function caches(obj) {
99226             function cloneCache(source) {
99227               var target = {};
99228               Object.keys(source).forEach(function (k) {
99229                 if (k === 'rtree') {
99230                   target.rtree = new RBush().fromJSON(source.rtree.toJSON()); // clone rbush
99231                 } else if (k === 'note') {
99232                   target.note = {};
99233                   Object.keys(source.note).forEach(function (id) {
99234                     target.note[id] = osmNote(source.note[id]); // copy notes
99235                   });
99236                 } else {
99237                   target[k] = JSON.parse(JSON.stringify(source[k])); // clone deep
99238                 }
99239               });
99240               return target;
99241             }
99242
99243             if (!arguments.length) {
99244               return {
99245                 tile: cloneCache(_tileCache),
99246                 note: cloneCache(_noteCache),
99247                 user: cloneCache(_userCache)
99248               };
99249             } // access caches directly for testing (e.g., loading notes rtree)
99250
99251
99252             if (obj === 'get') {
99253               return {
99254                 tile: _tileCache,
99255                 note: _noteCache,
99256                 user: _userCache
99257               };
99258             }
99259
99260             if (obj.tile) {
99261               _tileCache = obj.tile;
99262               _tileCache.inflight = {};
99263             }
99264
99265             if (obj.note) {
99266               _noteCache = obj.note;
99267               _noteCache.inflight = {};
99268               _noteCache.inflightPost = {};
99269             }
99270
99271             if (obj.user) {
99272               _userCache = obj.user;
99273             }
99274
99275             return this;
99276           },
99277           logout: function logout() {
99278             _userChangesets = undefined;
99279             _userDetails = undefined;
99280             oauth.logout();
99281             dispatch$2.call('change');
99282             return this;
99283           },
99284           authenticated: function authenticated() {
99285             return oauth.authenticated();
99286           },
99287           authenticate: function authenticate(callback) {
99288             var that = this;
99289             var cid = _connectionID;
99290             _userChangesets = undefined;
99291             _userDetails = undefined;
99292
99293             function done(err, res) {
99294               if (err) {
99295                 if (callback) callback(err);
99296                 return;
99297               }
99298
99299               if (that.getConnectionId() !== cid) {
99300                 if (callback) callback({
99301                   message: 'Connection Switched',
99302                   status: -1
99303                 });
99304                 return;
99305               }
99306
99307               _rateLimitError = undefined;
99308               dispatch$2.call('change');
99309               if (callback) callback(err, res);
99310               that.userChangesets(function () {}); // eagerly load user details/changesets
99311             }
99312
99313             return oauth.authenticate(done);
99314           },
99315           imageryBlocklists: function imageryBlocklists() {
99316             return _imageryBlocklists;
99317           },
99318           tileZoom: function tileZoom(val) {
99319             if (!arguments.length) return _tileZoom;
99320             _tileZoom = val;
99321             return this;
99322           },
99323           // get all cached notes covering the viewport
99324           notes: function notes(projection) {
99325             var viewport = projection.clipExtent();
99326             var min = [viewport[0][0], viewport[1][1]];
99327             var max = [viewport[1][0], viewport[0][1]];
99328             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
99329             return _noteCache.rtree.search(bbox).map(function (d) {
99330               return d.data;
99331             });
99332           },
99333           // get a single note from the cache
99334           getNote: function getNote(id) {
99335             return _noteCache.note[id];
99336           },
99337           // remove a single note from the cache
99338           removeNote: function removeNote(note) {
99339             if (!(note instanceof osmNote) || !note.id) return;
99340             delete _noteCache.note[note.id];
99341             updateRtree(encodeNoteRtree(note), false); // false = remove
99342           },
99343           // replace a single note in the cache
99344           replaceNote: function replaceNote(note) {
99345             if (!(note instanceof osmNote) || !note.id) return;
99346             _noteCache.note[note.id] = note;
99347             updateRtree(encodeNoteRtree(note), true); // true = replace
99348
99349             return note;
99350           },
99351           // Get an array of note IDs closed during this session.
99352           // Used to populate `closed:note` changeset tag
99353           getClosedIDs: function getClosedIDs() {
99354             return Object.keys(_noteCache.closed).sort();
99355           }
99356         };
99357
99358         var _apibase$1 = 'https://wiki.openstreetmap.org/w/api.php';
99359         var _inflight$1 = {};
99360         var _wikibaseCache = {};
99361         var _localeIDs = {
99362           en: false
99363         };
99364
99365         var debouncedRequest$1 = debounce(request$1, 500, {
99366           leading: false
99367         });
99368
99369         function request$1(url, callback) {
99370           if (_inflight$1[url]) return;
99371           var controller = new AbortController();
99372           _inflight$1[url] = controller;
99373           d3_json(url, {
99374             signal: controller.signal
99375           }).then(function (result) {
99376             delete _inflight$1[url];
99377             if (callback) callback(null, result);
99378           })["catch"](function (err) {
99379             delete _inflight$1[url];
99380             if (err.name === 'AbortError') return;
99381             if (callback) callback(err.message);
99382           });
99383         }
99384
99385         var serviceOsmWikibase = {
99386           init: function init() {
99387             _inflight$1 = {};
99388             _wikibaseCache = {};
99389             _localeIDs = {};
99390           },
99391           reset: function reset() {
99392             Object.values(_inflight$1).forEach(function (controller) {
99393               controller.abort();
99394             });
99395             _inflight$1 = {};
99396           },
99397
99398           /**
99399            * Get the best value for the property, or undefined if not found
99400            * @param entity object from wikibase
99401            * @param property string e.g. 'P4' for image
99402            * @param langCode string e.g. 'fr' for French
99403            */
99404           claimToValue: function claimToValue(entity, property, langCode) {
99405             if (!entity.claims[property]) return undefined;
99406             var locale = _localeIDs[langCode];
99407             var preferredPick, localePick;
99408             entity.claims[property].forEach(function (stmt) {
99409               // If exists, use value limited to the needed language (has a qualifier P26 = locale)
99410               // Or if not found, use the first value with the "preferred" rank
99411               if (!preferredPick && stmt.rank === 'preferred') {
99412                 preferredPick = stmt;
99413               }
99414
99415               if (locale && stmt.qualifiers && stmt.qualifiers.P26 && stmt.qualifiers.P26[0].datavalue.value.id === locale) {
99416                 localePick = stmt;
99417               }
99418             });
99419             var result = localePick || preferredPick;
99420
99421             if (result) {
99422               var datavalue = result.mainsnak.datavalue;
99423               return datavalue.type === 'wikibase-entityid' ? datavalue.value.id : datavalue.value;
99424             } else {
99425               return undefined;
99426             }
99427           },
99428
99429           /**
99430            * Convert monolingual property into a key-value object (language -> value)
99431            * @param entity object from wikibase
99432            * @param property string e.g. 'P31' for monolingual wiki page title
99433            */
99434           monolingualClaimToValueObj: function monolingualClaimToValueObj(entity, property) {
99435             if (!entity || !entity.claims[property]) return undefined;
99436             return entity.claims[property].reduce(function (acc, obj) {
99437               var value = obj.mainsnak.datavalue.value;
99438               acc[value.language] = value.text;
99439               return acc;
99440             }, {});
99441           },
99442           toSitelink: function toSitelink(key, value) {
99443             var result = value ? 'Tag:' + key + '=' + value : 'Key:' + key;
99444             return result.replace(/_/g, ' ').trim();
99445           },
99446           //
99447           // Pass params object of the form:
99448           // {
99449           //   key: 'string',
99450           //   value: 'string',
99451           //   langCode: 'string'
99452           // }
99453           //
99454           getEntity: function getEntity(params, callback) {
99455             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
99456             var that = this;
99457             var titles = [];
99458             var result = {};
99459             var rtypeSitelink = params.key === 'type' && params.value ? ('Relation:' + params.value).replace(/_/g, ' ').trim() : false;
99460             var keySitelink = params.key ? this.toSitelink(params.key) : false;
99461             var tagSitelink = params.key && params.value ? this.toSitelink(params.key, params.value) : false;
99462             var localeSitelink;
99463
99464             if (params.langCodes) {
99465               params.langCodes.forEach(function (langCode) {
99466                 if (_localeIDs[langCode] === undefined) {
99467                   // If this is the first time we are asking about this locale,
99468                   // fetch corresponding entity (if it exists), and cache it.
99469                   // If there is no such entry, cache `false` value to avoid re-requesting it.
99470                   localeSitelink = ('Locale:' + langCode).replace(/_/g, ' ').trim();
99471                   titles.push(localeSitelink);
99472                 }
99473               });
99474             }
99475
99476             if (rtypeSitelink) {
99477               if (_wikibaseCache[rtypeSitelink]) {
99478                 result.rtype = _wikibaseCache[rtypeSitelink];
99479               } else {
99480                 titles.push(rtypeSitelink);
99481               }
99482             }
99483
99484             if (keySitelink) {
99485               if (_wikibaseCache[keySitelink]) {
99486                 result.key = _wikibaseCache[keySitelink];
99487               } else {
99488                 titles.push(keySitelink);
99489               }
99490             }
99491
99492             if (tagSitelink) {
99493               if (_wikibaseCache[tagSitelink]) {
99494                 result.tag = _wikibaseCache[tagSitelink];
99495               } else {
99496                 titles.push(tagSitelink);
99497               }
99498             }
99499
99500             if (!titles.length) {
99501               // Nothing to do, we already had everything in the cache
99502               return callback(null, result);
99503             } // Requesting just the user language code
99504             // If backend recognizes the code, it will perform proper fallbacks,
99505             // and the result will contain the requested code. If not, all values are returned:
99506             // {"zh-tw":{"value":"...","language":"zh-tw","source-language":"zh-hant"}
99507             // {"pt-br":{"value":"...","language":"pt","for-language":"pt-br"}}
99508
99509
99510             var obj = {
99511               action: 'wbgetentities',
99512               sites: 'wiki',
99513               titles: titles.join('|'),
99514               languages: params.langCodes.join('|'),
99515               languagefallback: 1,
99516               origin: '*',
99517               format: 'json' // There is an MW Wikibase API bug https://phabricator.wikimedia.org/T212069
99518               // We shouldn't use v1 until it gets fixed, but should switch to it afterwards
99519               // formatversion: 2,
99520
99521             };
99522             var url = _apibase$1 + '?' + utilQsString(obj);
99523             doRequest(url, function (err, d) {
99524               if (err) {
99525                 callback(err);
99526               } else if (!d.success || d.error) {
99527                 callback(d.error.messages.map(function (v) {
99528                   return v.html['*'];
99529                 }).join('<br>'));
99530               } else {
99531                 var localeID = false;
99532                 Object.values(d.entities).forEach(function (res) {
99533                   if (res.missing !== '') {
99534                     var title = res.sitelinks.wiki.title;
99535
99536                     if (title === rtypeSitelink) {
99537                       _wikibaseCache[rtypeSitelink] = res;
99538                       result.rtype = res;
99539                     } else if (title === keySitelink) {
99540                       _wikibaseCache[keySitelink] = res;
99541                       result.key = res;
99542                     } else if (title === tagSitelink) {
99543                       _wikibaseCache[tagSitelink] = res;
99544                       result.tag = res;
99545                     } else if (title === localeSitelink) {
99546                       localeID = res.id;
99547                     } else {
99548                       console.log('Unexpected title ' + title); // eslint-disable-line no-console
99549                     }
99550                   }
99551                 });
99552
99553                 if (localeSitelink) {
99554                   // If locale ID is not found, store false to prevent repeated queries
99555                   that.addLocale(params.langCodes[0], localeID);
99556                 }
99557
99558                 callback(null, result);
99559               }
99560             });
99561           },
99562           //
99563           // Pass params object of the form:
99564           // {
99565           //   key: 'string',     // required
99566           //   value: 'string'    // optional
99567           // }
99568           //
99569           // Get an result object used to display tag documentation
99570           // {
99571           //   title:        'string',
99572           //   description:  'string',
99573           //   editURL:      'string',
99574           //   imageURL:     'string',
99575           //   wiki:         { title: 'string', text: 'string', url: 'string' }
99576           // }
99577           //
99578           getDocs: function getDocs(params, callback) {
99579             var that = this;
99580             var langCodes = _mainLocalizer.localeCodes().map(function (code) {
99581               return code.toLowerCase();
99582             });
99583             params.langCodes = langCodes;
99584             this.getEntity(params, function (err, data) {
99585               if (err) {
99586                 callback(err);
99587                 return;
99588               }
99589
99590               var entity = data.rtype || data.tag || data.key;
99591
99592               if (!entity) {
99593                 callback('No entity');
99594                 return;
99595               }
99596
99597               var i;
99598               var description;
99599
99600               for (i in langCodes) {
99601                 var _code = langCodes[i];
99602
99603                 if (entity.descriptions[_code] && entity.descriptions[_code].language === _code) {
99604                   description = entity.descriptions[_code];
99605                   break;
99606                 }
99607               }
99608
99609               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
99610
99611               var result = {
99612                 title: entity.title,
99613                 description: description ? description.value : '',
99614                 descriptionLocaleCode: description ? description.language : '',
99615                 editURL: 'https://wiki.openstreetmap.org/wiki/' + entity.title
99616               }; // add image
99617
99618               if (entity.claims) {
99619                 var imageroot;
99620                 var image = that.claimToValue(entity, 'P4', langCodes[0]);
99621
99622                 if (image) {
99623                   imageroot = 'https://commons.wikimedia.org/w/index.php';
99624                 } else {
99625                   image = that.claimToValue(entity, 'P28', langCodes[0]);
99626
99627                   if (image) {
99628                     imageroot = 'https://wiki.openstreetmap.org/w/index.php';
99629                   }
99630                 }
99631
99632                 if (imageroot && image) {
99633                   result.imageURL = imageroot + '?' + utilQsString({
99634                     title: 'Special:Redirect/file/' + image,
99635                     width: 400
99636                   });
99637                 }
99638               } // Try to get a wiki page from tag data item first, followed by the corresponding key data item.
99639               // If neither tag nor key data item contain a wiki page in the needed language nor English,
99640               // get the first found wiki page from either the tag or the key item.
99641
99642
99643               var rtypeWiki = that.monolingualClaimToValueObj(data.rtype, 'P31');
99644               var tagWiki = that.monolingualClaimToValueObj(data.tag, 'P31');
99645               var keyWiki = that.monolingualClaimToValueObj(data.key, 'P31');
99646               var wikis = [rtypeWiki, tagWiki, keyWiki];
99647
99648               for (i in wikis) {
99649                 var wiki = wikis[i];
99650
99651                 for (var j in langCodes) {
99652                   var code = langCodes[j];
99653                   var referenceId = langCodes[0].split('-')[0] !== 'en' && code.split('-')[0] === 'en' ? 'inspector.wiki_en_reference' : 'inspector.wiki_reference';
99654                   var info = getWikiInfo(wiki, code, referenceId);
99655
99656                   if (info) {
99657                     result.wiki = info;
99658                     break;
99659                   }
99660                 }
99661
99662                 if (result.wiki) break;
99663               }
99664
99665               callback(null, result); // Helper method to get wiki info if a given language exists
99666
99667               function getWikiInfo(wiki, langCode, tKey) {
99668                 if (wiki && wiki[langCode]) {
99669                   return {
99670                     title: wiki[langCode],
99671                     text: tKey,
99672                     url: 'https://wiki.openstreetmap.org/wiki/' + wiki[langCode]
99673                   };
99674                 }
99675               }
99676             });
99677           },
99678           addLocale: function addLocale(langCode, qid) {
99679             // Makes it easier to unit test
99680             _localeIDs[langCode] = qid;
99681           },
99682           apibase: function apibase(val) {
99683             if (!arguments.length) return _apibase$1;
99684             _apibase$1 = val;
99685             return this;
99686           }
99687         };
99688
99689         var jsonpCache = {};
99690         window.jsonpCache = jsonpCache;
99691         function jsonpRequest(url, callback) {
99692           var request = {
99693             abort: function abort() {}
99694           };
99695
99696           if (window.JSONP_FIX) {
99697             if (window.JSONP_DELAY === 0) {
99698               callback(window.JSONP_FIX);
99699             } else {
99700               var t = window.setTimeout(function () {
99701                 callback(window.JSONP_FIX);
99702               }, window.JSONP_DELAY || 0);
99703
99704               request.abort = function () {
99705                 window.clearTimeout(t);
99706               };
99707             }
99708
99709             return request;
99710           }
99711
99712           function rand() {
99713             var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
99714             var c = '';
99715             var i = -1;
99716
99717             while (++i < 15) {
99718               c += chars.charAt(Math.floor(Math.random() * 52));
99719             }
99720
99721             return c;
99722           }
99723
99724           function create(url) {
99725             var e = url.match(/callback=(\w+)/);
99726             var c = e ? e[1] : rand();
99727
99728             jsonpCache[c] = function (data) {
99729               if (jsonpCache[c]) {
99730                 callback(data);
99731               }
99732
99733               finalize();
99734             };
99735
99736             function finalize() {
99737               delete jsonpCache[c];
99738               script.remove();
99739             }
99740
99741             request.abort = finalize;
99742             return 'jsonpCache.' + c;
99743           }
99744
99745           var cb = create(url);
99746           var script = select('head').append('script').attr('type', 'text/javascript').attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
99747           return request;
99748         }
99749
99750         var bubbleApi = 'https://dev.virtualearth.net/mapcontrol/HumanScaleServices/GetBubbles.ashx?';
99751         var streetsideImagesApi = 'https://t.ssl.ak.tiles.virtualearth.net/tiles/';
99752         var bubbleAppKey = 'AuftgJsO0Xs8Ts4M1xZUQJQXJNsvmh3IV8DkNieCiy3tCwCUMq76-WpkrBtNAuEm';
99753         var pannellumViewerCSS = 'pannellum-streetside/pannellum.css';
99754         var pannellumViewerJS = 'pannellum-streetside/pannellum.js';
99755         var maxResults = 2000;
99756         var tileZoom = 16.5;
99757         var tiler$1 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
99758         var dispatch$1 = dispatch$8('loadedImages', 'viewerChanged');
99759         var minHfov = 10; // zoom in degrees:  20, 10, 5
99760
99761         var maxHfov = 90; // zoom out degrees
99762
99763         var defaultHfov = 45;
99764         var _hires = false;
99765         var _resolution = 512; // higher numbers are slower - 512, 1024, 2048, 4096
99766
99767         var _currScene = 0;
99768
99769         var _ssCache;
99770
99771         var _pannellumViewer;
99772
99773         var _sceneOptions = {
99774           showFullscreenCtrl: false,
99775           autoLoad: true,
99776           compass: true,
99777           yaw: 0,
99778           minHfov: minHfov,
99779           maxHfov: maxHfov,
99780           hfov: defaultHfov,
99781           type: 'cubemap',
99782           cubeMap: []
99783         };
99784
99785         var _loadViewerPromise;
99786         /**
99787          * abortRequest().
99788          */
99789
99790
99791         function abortRequest$1(i) {
99792           i.abort();
99793         }
99794         /**
99795          * localeTimeStamp().
99796          */
99797
99798
99799         function localeTimestamp(s) {
99800           if (!s) return null;
99801           var options = {
99802             day: 'numeric',
99803             month: 'short',
99804             year: 'numeric'
99805           };
99806           var d = new Date(s);
99807           if (isNaN(d.getTime())) return null;
99808           return d.toLocaleString(_mainLocalizer.localeCode(), options);
99809         }
99810         /**
99811          * loadTiles() wraps the process of generating tiles and then fetching image points for each tile.
99812          */
99813
99814
99815         function loadTiles(which, url, projection, margin) {
99816           var tiles = tiler$1.margin(margin).getTiles(projection); // abort inflight requests that are no longer needed
99817
99818           var cache = _ssCache[which];
99819           Object.keys(cache.inflight).forEach(function (k) {
99820             var wanted = tiles.find(function (tile) {
99821               return k.indexOf(tile.id + ',') === 0;
99822             });
99823
99824             if (!wanted) {
99825               abortRequest$1(cache.inflight[k]);
99826               delete cache.inflight[k];
99827             }
99828           });
99829           tiles.forEach(function (tile) {
99830             return loadNextTilePage(which, url, tile);
99831           });
99832         }
99833         /**
99834          * loadNextTilePage() load data for the next tile page in line.
99835          */
99836
99837
99838         function loadNextTilePage(which, url, tile) {
99839           var cache = _ssCache[which];
99840           var nextPage = cache.nextPage[tile.id] || 0;
99841           var id = tile.id + ',' + String(nextPage);
99842           if (cache.loaded[id] || cache.inflight[id]) return;
99843           cache.inflight[id] = getBubbles(url, tile, function (bubbles) {
99844             cache.loaded[id] = true;
99845             delete cache.inflight[id];
99846             if (!bubbles) return; // [].shift() removes the first element, some statistics info, not a bubble point
99847
99848             bubbles.shift();
99849             var features = bubbles.map(function (bubble) {
99850               if (cache.points[bubble.id]) return null; // skip duplicates
99851
99852               var loc = [bubble.lo, bubble.la];
99853               var d = {
99854                 loc: loc,
99855                 key: bubble.id,
99856                 ca: bubble.he,
99857                 captured_at: bubble.cd,
99858                 captured_by: 'microsoft',
99859                 // nbn: bubble.nbn,
99860                 // pbn: bubble.pbn,
99861                 // ad: bubble.ad,
99862                 // rn: bubble.rn,
99863                 pr: bubble.pr,
99864                 // previous
99865                 ne: bubble.ne,
99866                 // next
99867                 pano: true,
99868                 sequenceKey: null
99869               };
99870               cache.points[bubble.id] = d; // a sequence starts here
99871
99872               if (bubble.pr === undefined) {
99873                 cache.leaders.push(bubble.id);
99874               }
99875
99876               return {
99877                 minX: loc[0],
99878                 minY: loc[1],
99879                 maxX: loc[0],
99880                 maxY: loc[1],
99881                 data: d
99882               };
99883             }).filter(Boolean);
99884             cache.rtree.load(features);
99885             connectSequences();
99886
99887             if (which === 'bubbles') {
99888               dispatch$1.call('loadedImages');
99889             }
99890           });
99891         } // call this sometimes to connect the bubbles into sequences
99892
99893
99894         function connectSequences() {
99895           var cache = _ssCache.bubbles;
99896           var keepLeaders = [];
99897
99898           for (var i = 0; i < cache.leaders.length; i++) {
99899             var bubble = cache.points[cache.leaders[i]];
99900             var seen = {}; // try to make a sequence.. use the key of the leader bubble.
99901
99902             var sequence = {
99903               key: bubble.key,
99904               bubbles: []
99905             };
99906             var complete = false;
99907
99908             do {
99909               sequence.bubbles.push(bubble);
99910               seen[bubble.key] = true;
99911
99912               if (bubble.ne === undefined) {
99913                 complete = true;
99914               } else {
99915                 bubble = cache.points[bubble.ne]; // advance to next
99916               }
99917             } while (bubble && !seen[bubble.key] && !complete);
99918
99919             if (complete) {
99920               _ssCache.sequences[sequence.key] = sequence; // assign bubbles to the sequence
99921
99922               for (var j = 0; j < sequence.bubbles.length; j++) {
99923                 sequence.bubbles[j].sequenceKey = sequence.key;
99924               } // create a GeoJSON LineString
99925
99926
99927               sequence.geojson = {
99928                 type: 'LineString',
99929                 properties: {
99930                   captured_at: sequence.bubbles[0] ? sequence.bubbles[0].captured_at : null,
99931                   captured_by: sequence.bubbles[0] ? sequence.bubbles[0].captured_by : null,
99932                   key: sequence.key
99933                 },
99934                 coordinates: sequence.bubbles.map(function (d) {
99935                   return d.loc;
99936                 })
99937               };
99938             } else {
99939               keepLeaders.push(cache.leaders[i]);
99940             }
99941           } // couldn't complete these, save for later
99942
99943
99944           cache.leaders = keepLeaders;
99945         }
99946         /**
99947          * getBubbles() handles the request to the server for a tile extent of 'bubbles' (streetside image locations).
99948          */
99949
99950
99951         function getBubbles(url, tile, callback) {
99952           var rect = tile.extent.rectangle();
99953           var urlForRequest = url + utilQsString({
99954             n: rect[3],
99955             s: rect[1],
99956             e: rect[2],
99957             w: rect[0],
99958             c: maxResults,
99959             appkey: bubbleAppKey,
99960             jsCallback: '{callback}'
99961           });
99962           return jsonpRequest(urlForRequest, function (data) {
99963             if (!data || data.error) {
99964               callback(null);
99965             } else {
99966               callback(data);
99967             }
99968           });
99969         } // partition viewport into higher zoom tiles
99970
99971
99972         function partitionViewport(projection) {
99973           var z = geoScaleToZoom(projection.scale());
99974           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
99975
99976           var tiler = utilTiler().zoomExtent([z2, z2]);
99977           return tiler.getTiles(projection).map(function (tile) {
99978             return tile.extent;
99979           });
99980         } // no more than `limit` results per partition.
99981
99982
99983         function searchLimited(limit, projection, rtree) {
99984           limit = limit || 5;
99985           return partitionViewport(projection).reduce(function (result, extent) {
99986             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
99987               return d.data;
99988             });
99989             return found.length ? result.concat(found) : result;
99990           }, []);
99991         }
99992         /**
99993          * loadImage()
99994          */
99995
99996
99997         function loadImage(imgInfo) {
99998           return new Promise(function (resolve) {
99999             var img = new Image();
100000
100001             img.onload = function () {
100002               var canvas = document.getElementById('ideditor-canvas' + imgInfo.face);
100003               var ctx = canvas.getContext('2d');
100004               ctx.drawImage(img, imgInfo.x, imgInfo.y);
100005               resolve({
100006                 imgInfo: imgInfo,
100007                 status: 'ok'
100008               });
100009             };
100010
100011             img.onerror = function () {
100012               resolve({
100013                 data: imgInfo,
100014                 status: 'error'
100015               });
100016             };
100017
100018             img.setAttribute('crossorigin', '');
100019             img.src = imgInfo.url;
100020           });
100021         }
100022         /**
100023          * loadCanvas()
100024          */
100025
100026
100027         function loadCanvas(imageGroup) {
100028           return Promise.all(imageGroup.map(loadImage)).then(function (data) {
100029             var canvas = document.getElementById('ideditor-canvas' + data[0].imgInfo.face);
100030             var which = {
100031               '01': 0,
100032               '02': 1,
100033               '03': 2,
100034               '10': 3,
100035               '11': 4,
100036               '12': 5
100037             };
100038             var face = data[0].imgInfo.face;
100039             _sceneOptions.cubeMap[which[face]] = canvas.toDataURL('image/jpeg', 1.0);
100040             return {
100041               status: 'loadCanvas for face ' + data[0].imgInfo.face + 'ok'
100042             };
100043           });
100044         }
100045         /**
100046          * loadFaces()
100047          */
100048
100049
100050         function loadFaces(faceGroup) {
100051           return Promise.all(faceGroup.map(loadCanvas)).then(function () {
100052             return {
100053               status: 'loadFaces done'
100054             };
100055           });
100056         }
100057
100058         function setupCanvas(selection, reset) {
100059           if (reset) {
100060             selection.selectAll('#ideditor-stitcher-canvases').remove();
100061           } // Add the Streetside working canvases. These are used for 'stitching', or combining,
100062           // multiple images for each of the six faces, before passing to the Pannellum control as DataUrls
100063
100064
100065           selection.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', function (d) {
100066             return 'ideditor-' + d;
100067           }).attr('width', _resolution).attr('height', _resolution);
100068         }
100069
100070         function qkToXY(qk) {
100071           var x = 0;
100072           var y = 0;
100073           var scale = 256;
100074
100075           for (var i = qk.length; i > 0; i--) {
100076             var key = qk[i - 1];
100077             x += +(key === '1' || key === '3') * scale;
100078             y += +(key === '2' || key === '3') * scale;
100079             scale *= 2;
100080           }
100081
100082           return [x, y];
100083         }
100084
100085         function getQuadKeys() {
100086           var dim = _resolution / 256;
100087           var quadKeys;
100088
100089           if (dim === 16) {
100090             quadKeys = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111', '0002', '0003', '0012', '0013', '0102', '0103', '0112', '0113', '1002', '1003', '1012', '1013', '1102', '1103', '1112', '1113', '0020', '0021', '0030', '0031', '0120', '0121', '0130', '0131', '1020', '1021', '1030', '1031', '1120', '1121', '1130', '1131', '0022', '0023', '0032', '0033', '0122', '0123', '0132', '0133', '1022', '1023', '1032', '1033', '1122', '1123', '1132', '1133', '0200', '0201', '0210', '0211', '0300', '0301', '0310', '0311', '1200', '1201', '1210', '1211', '1300', '1301', '1310', '1311', '0202', '0203', '0212', '0213', '0302', '0303', '0312', '0313', '1202', '1203', '1212', '1213', '1302', '1303', '1312', '1313', '0220', '0221', '0230', '0231', '0320', '0321', '0330', '0331', '1220', '1221', '1230', '1231', '1320', '1321', '1330', '1331', '0222', '0223', '0232', '0233', '0322', '0323', '0332', '0333', '1222', '1223', '1232', '1233', '1322', '1323', '1332', '1333', '2000', '2001', '2010', '2011', '2100', '2101', '2110', '2111', '3000', '3001', '3010', '3011', '3100', '3101', '3110', '3111', '2002', '2003', '2012', '2013', '2102', '2103', '2112', '2113', '3002', '3003', '3012', '3013', '3102', '3103', '3112', '3113', '2020', '2021', '2030', '2031', '2120', '2121', '2130', '2131', '3020', '3021', '3030', '3031', '3120', '3121', '3130', '3131', '2022', '2023', '2032', '2033', '2122', '2123', '2132', '2133', '3022', '3023', '3032', '3033', '3122', '3123', '3132', '3133', '2200', '2201', '2210', '2211', '2300', '2301', '2310', '2311', '3200', '3201', '3210', '3211', '3300', '3301', '3310', '3311', '2202', '2203', '2212', '2213', '2302', '2303', '2312', '2313', '3202', '3203', '3212', '3213', '3302', '3303', '3312', '3313', '2220', '2221', '2230', '2231', '2320', '2321', '2330', '2331', '3220', '3221', '3230', '3231', '3320', '3321', '3330', '3331', '2222', '2223', '2232', '2233', '2322', '2323', '2332', '2333', '3222', '3223', '3232', '3233', '3322', '3323', '3332', '3333'];
100091           } else if (dim === 8) {
100092             quadKeys = ['000', '001', '010', '011', '100', '101', '110', '111', '002', '003', '012', '013', '102', '103', '112', '113', '020', '021', '030', '031', '120', '121', '130', '131', '022', '023', '032', '033', '122', '123', '132', '133', '200', '201', '210', '211', '300', '301', '310', '311', '202', '203', '212', '213', '302', '303', '312', '313', '220', '221', '230', '231', '320', '321', '330', '331', '222', '223', '232', '233', '322', '323', '332', '333'];
100093           } else if (dim === 4) {
100094             quadKeys = ['00', '01', '10', '11', '02', '03', '12', '13', '20', '21', '30', '31', '22', '23', '32', '33'];
100095           } else {
100096             // dim === 2
100097             quadKeys = ['0', '1', '2', '3'];
100098           }
100099
100100           return quadKeys;
100101         }
100102
100103         var serviceStreetside = {
100104           /**
100105            * init() initialize streetside.
100106            */
100107           init: function init() {
100108             if (!_ssCache) {
100109               this.reset();
100110             }
100111
100112             this.event = utilRebind(this, dispatch$1, 'on');
100113           },
100114
100115           /**
100116            * reset() reset the cache.
100117            */
100118           reset: function reset() {
100119             if (_ssCache) {
100120               Object.values(_ssCache.bubbles.inflight).forEach(abortRequest$1);
100121             }
100122
100123             _ssCache = {
100124               bubbles: {
100125                 inflight: {},
100126                 loaded: {},
100127                 nextPage: {},
100128                 rtree: new RBush(),
100129                 points: {},
100130                 leaders: []
100131               },
100132               sequences: {}
100133             };
100134           },
100135
100136           /**
100137            * bubbles()
100138            */
100139           bubbles: function bubbles(projection) {
100140             var limit = 5;
100141             return searchLimited(limit, projection, _ssCache.bubbles.rtree);
100142           },
100143           cachedImage: function cachedImage(imageKey) {
100144             return _ssCache.bubbles.points[imageKey];
100145           },
100146           sequences: function sequences(projection) {
100147             var viewport = projection.clipExtent();
100148             var min = [viewport[0][0], viewport[1][1]];
100149             var max = [viewport[1][0], viewport[0][1]];
100150             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
100151             var seen = {};
100152             var results = []; // all sequences for bubbles in viewport
100153
100154             _ssCache.bubbles.rtree.search(bbox).forEach(function (d) {
100155               var key = d.data.sequenceKey;
100156
100157               if (key && !seen[key]) {
100158                 seen[key] = true;
100159                 results.push(_ssCache.sequences[key].geojson);
100160               }
100161             });
100162
100163             return results;
100164           },
100165
100166           /**
100167            * loadBubbles()
100168            */
100169           loadBubbles: function loadBubbles(projection, margin) {
100170             // by default: request 2 nearby tiles so we can connect sequences.
100171             if (margin === undefined) margin = 2;
100172             loadTiles('bubbles', bubbleApi, projection, margin);
100173           },
100174           viewer: function viewer() {
100175             return _pannellumViewer;
100176           },
100177           initViewer: function initViewer() {
100178             if (!window.pannellum) return;
100179             if (_pannellumViewer) return;
100180             _currScene += 1;
100181
100182             var sceneID = _currScene.toString();
100183
100184             var options = {
100185               'default': {
100186                 firstScene: sceneID
100187               },
100188               scenes: {}
100189             };
100190             options.scenes[sceneID] = _sceneOptions;
100191             _pannellumViewer = window.pannellum.viewer('ideditor-viewer-streetside', options);
100192           },
100193           ensureViewerLoaded: function ensureViewerLoaded(context) {
100194             if (_loadViewerPromise) return _loadViewerPromise; // create ms-wrapper, a photo wrapper class
100195
100196             var wrap = context.container().select('.photoviewer').selectAll('.ms-wrapper').data([0]); // inject ms-wrapper into the photoviewer div
100197             // (used by all to house each custom photo viewer)
100198
100199             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper ms-wrapper').classed('hide', true);
100200             var that = this;
100201             var pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // inject div to support streetside viewer (pannellum) and attribution line
100202
100203             wrapEnter.append('div').attr('id', 'ideditor-viewer-streetside').on(pointerPrefix + 'down.streetside', function () {
100204               select(window).on(pointerPrefix + 'move.streetside', function () {
100205                 dispatch$1.call('viewerChanged');
100206               }, true);
100207             }).on(pointerPrefix + 'up.streetside pointercancel.streetside', function () {
100208               select(window).on(pointerPrefix + 'move.streetside', null); // continue dispatching events for a few seconds, in case viewer has inertia.
100209
100210               var t = timer(function (elapsed) {
100211                 dispatch$1.call('viewerChanged');
100212
100213                 if (elapsed > 2000) {
100214                   t.stop();
100215                 }
100216               });
100217             }).append('div').attr('class', 'photo-attribution fillD');
100218             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
100219             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
100220             controlsEnter.append('button').on('click.forward', step(1)).html('►'); // create working canvas for stitching together images
100221
100222             wrap = wrap.merge(wrapEnter).call(setupCanvas, true); // Register viewer resize handler
100223
100224             context.ui().photoviewer.on('resize.streetside', function () {
100225               if (_pannellumViewer) {
100226                 _pannellumViewer.resize();
100227               }
100228             });
100229             _loadViewerPromise = new Promise(function (resolve, reject) {
100230               var loadedCount = 0;
100231
100232               function loaded() {
100233                 loadedCount += 1; // wait until both files are loaded
100234
100235                 if (loadedCount === 2) resolve();
100236               }
100237
100238               var head = select('head'); // load streetside pannellum viewer css
100239
100240               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 () {
100241                 reject();
100242               }); // load streetside pannellum viewer js
100243
100244               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 () {
100245                 reject();
100246               });
100247             })["catch"](function () {
100248               _loadViewerPromise = null;
100249             });
100250             return _loadViewerPromise;
100251
100252             function step(stepBy) {
100253               return function () {
100254                 var viewer = context.container().select('.photoviewer');
100255                 var selected = viewer.empty() ? undefined : viewer.datum();
100256                 if (!selected) return;
100257                 var nextID = stepBy === 1 ? selected.ne : selected.pr;
100258
100259                 var yaw = _pannellumViewer.getYaw();
100260
100261                 var ca = selected.ca + yaw;
100262                 var origin = selected.loc; // construct a search trapezoid pointing out from current bubble
100263
100264                 var meters = 35;
100265                 var p1 = [origin[0] + geoMetersToLon(meters / 5, origin[1]), origin[1]];
100266                 var p2 = [origin[0] + geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
100267                 var p3 = [origin[0] - geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
100268                 var p4 = [origin[0] - geoMetersToLon(meters / 5, origin[1]), origin[1]];
100269                 var poly = [p1, p2, p3, p4, p1]; // rotate it to face forward/backward
100270
100271                 var angle = (stepBy === 1 ? ca : ca + 180) * (Math.PI / 180);
100272                 poly = geoRotate(poly, -angle, origin);
100273                 var extent = poly.reduce(function (extent, point) {
100274                   return extent.extend(geoExtent(point));
100275                 }, geoExtent()); // find nearest other bubble in the search polygon
100276
100277                 var minDist = Infinity;
100278
100279                 _ssCache.bubbles.rtree.search(extent.bbox()).forEach(function (d) {
100280                   if (d.data.key === selected.key) return;
100281                   if (!geoPointInPolygon(d.data.loc, poly)) return;
100282                   var dist = geoVecLength(d.data.loc, selected.loc);
100283                   var theta = selected.ca - d.data.ca;
100284                   var minTheta = Math.min(Math.abs(theta), 360 - Math.abs(theta));
100285
100286                   if (minTheta > 20) {
100287                     dist += 5; // penalize distance if camera angles don't match
100288                   }
100289
100290                   if (dist < minDist) {
100291                     nextID = d.data.key;
100292                     minDist = dist;
100293                   }
100294                 });
100295
100296                 var nextBubble = nextID && that.cachedImage(nextID);
100297                 if (!nextBubble) return;
100298                 context.map().centerEase(nextBubble.loc);
100299                 that.selectImage(context, nextBubble.key).yaw(yaw).showViewer(context);
100300               };
100301             }
100302           },
100303           yaw: function yaw(_yaw) {
100304             if (typeof _yaw !== 'number') return _yaw;
100305             _sceneOptions.yaw = _yaw;
100306             return this;
100307           },
100308
100309           /**
100310            * showViewer()
100311            */
100312           showViewer: function showViewer(context) {
100313             var wrap = context.container().select('.photoviewer').classed('hide', false);
100314             var isHidden = wrap.selectAll('.photo-wrapper.ms-wrapper.hide').size();
100315
100316             if (isHidden) {
100317               wrap.selectAll('.photo-wrapper:not(.ms-wrapper)').classed('hide', true);
100318               wrap.selectAll('.photo-wrapper.ms-wrapper').classed('hide', false);
100319             }
100320
100321             return this;
100322           },
100323
100324           /**
100325            * hideViewer()
100326            */
100327           hideViewer: function hideViewer(context) {
100328             var viewer = context.container().select('.photoviewer');
100329             if (!viewer.empty()) viewer.datum(null);
100330             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
100331             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
100332             this.updateUrlImage(null);
100333             return this.setStyles(context, null, true);
100334           },
100335
100336           /**
100337            * selectImage().
100338            */
100339           selectImage: function selectImage(context, key) {
100340             var that = this;
100341             var d = this.cachedImage(key);
100342             var viewer = context.container().select('.photoviewer');
100343             if (!viewer.empty()) viewer.datum(d);
100344             this.setStyles(context, null, true);
100345             var wrap = context.container().select('.photoviewer .ms-wrapper');
100346             var attribution = wrap.selectAll('.photo-attribution').html('');
100347             wrap.selectAll('.pnlm-load-box') // display "loading.."
100348             .style('display', 'block');
100349             if (!d) return this;
100350             this.updateUrlImage(key);
100351             _sceneOptions.northOffset = d.ca;
100352             var line1 = attribution.append('div').attr('class', 'attribution-row');
100353             var hiresDomId = utilUniqueDomId('streetside-hires'); // Add hires checkbox
100354
100355             var label = line1.append('label').attr('for', hiresDomId).attr('class', 'streetside-hires');
100356             label.append('input').attr('type', 'checkbox').attr('id', hiresDomId).property('checked', _hires).on('click', function (d3_event) {
100357               d3_event.stopPropagation();
100358               _hires = !_hires;
100359               _resolution = _hires ? 1024 : 512;
100360               wrap.call(setupCanvas, true);
100361               var viewstate = {
100362                 yaw: _pannellumViewer.getYaw(),
100363                 pitch: _pannellumViewer.getPitch(),
100364                 hfov: _pannellumViewer.getHfov()
100365               };
100366               _sceneOptions = Object.assign(_sceneOptions, viewstate);
100367               that.selectImage(context, d.key).showViewer(context);
100368             });
100369             label.append('span').html(_t.html('streetside.hires'));
100370             var captureInfo = line1.append('div').attr('class', 'attribution-capture-info'); // Add capture date
100371
100372             if (d.captured_by) {
100373               var yyyy = new Date().getFullYear();
100374               captureInfo.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://www.microsoft.com/en-us/maps/streetside').html('©' + yyyy + ' Microsoft');
100375               captureInfo.append('span').html('|');
100376             }
100377
100378             if (d.captured_at) {
100379               captureInfo.append('span').attr('class', 'captured_at').html(localeTimestamp(d.captured_at));
100380             } // Add image links
100381
100382
100383             var line2 = attribution.append('div').attr('class', 'attribution-row');
100384             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').html(_t.html('streetside.view_on_bing'));
100385             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').html(_t.html('streetside.report'));
100386             var bubbleIdQuadKey = d.key.toString(4);
100387             var paddingNeeded = 16 - bubbleIdQuadKey.length;
100388
100389             for (var i = 0; i < paddingNeeded; i++) {
100390               bubbleIdQuadKey = '0' + bubbleIdQuadKey;
100391             }
100392
100393             var imgUrlPrefix = streetsideImagesApi + 'hs' + bubbleIdQuadKey;
100394             var imgUrlSuffix = '.jpg?g=6338&n=z'; // Cubemap face code order matters here: front=01, right=02, back=03, left=10, up=11, down=12
100395
100396             var faceKeys = ['01', '02', '03', '10', '11', '12']; // Map images to cube faces
100397
100398             var quadKeys = getQuadKeys();
100399             var faces = faceKeys.map(function (faceKey) {
100400               return quadKeys.map(function (quadKey) {
100401                 var xy = qkToXY(quadKey);
100402                 return {
100403                   face: faceKey,
100404                   url: imgUrlPrefix + faceKey + quadKey + imgUrlSuffix,
100405                   x: xy[0],
100406                   y: xy[1]
100407                 };
100408               });
100409             });
100410             loadFaces(faces).then(function () {
100411               if (!_pannellumViewer) {
100412                 that.initViewer();
100413               } else {
100414                 // make a new scene
100415                 _currScene += 1;
100416
100417                 var sceneID = _currScene.toString();
100418
100419                 _pannellumViewer.addScene(sceneID, _sceneOptions).loadScene(sceneID); // remove previous scene
100420
100421
100422                 if (_currScene > 2) {
100423                   sceneID = (_currScene - 1).toString();
100424
100425                   _pannellumViewer.removeScene(sceneID);
100426                 }
100427               }
100428             });
100429             return this;
100430           },
100431           getSequenceKeyForBubble: function getSequenceKeyForBubble(d) {
100432             return d && d.sequenceKey;
100433           },
100434           // Updates the currently highlighted sequence and selected bubble.
100435           // Reset is only necessary when interacting with the viewport because
100436           // this implicitly changes the currently selected bubble/sequence
100437           setStyles: function setStyles(context, hovered, reset) {
100438             if (reset) {
100439               // reset all layers
100440               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
100441               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
100442             }
100443
100444             var hoveredBubbleKey = hovered && hovered.key;
100445             var hoveredSequenceKey = this.getSequenceKeyForBubble(hovered);
100446             var hoveredSequence = hoveredSequenceKey && _ssCache.sequences[hoveredSequenceKey];
100447             var hoveredBubbleKeys = hoveredSequence && hoveredSequence.bubbles.map(function (d) {
100448               return d.key;
100449             }) || [];
100450             var viewer = context.container().select('.photoviewer');
100451             var selected = viewer.empty() ? undefined : viewer.datum();
100452             var selectedBubbleKey = selected && selected.key;
100453             var selectedSequenceKey = this.getSequenceKeyForBubble(selected);
100454             var selectedSequence = selectedSequenceKey && _ssCache.sequences[selectedSequenceKey];
100455             var selectedBubbleKeys = selectedSequence && selectedSequence.bubbles.map(function (d) {
100456               return d.key;
100457             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
100458
100459             var highlightedBubbleKeys = utilArrayUnion(hoveredBubbleKeys, selectedBubbleKeys);
100460             context.container().selectAll('.layer-streetside-images .viewfield-group').classed('highlighted', function (d) {
100461               return highlightedBubbleKeys.indexOf(d.key) !== -1;
100462             }).classed('hovered', function (d) {
100463               return d.key === hoveredBubbleKey;
100464             }).classed('currentView', function (d) {
100465               return d.key === selectedBubbleKey;
100466             });
100467             context.container().selectAll('.layer-streetside-images .sequence').classed('highlighted', function (d) {
100468               return d.properties.key === hoveredSequenceKey;
100469             }).classed('currentView', function (d) {
100470               return d.properties.key === selectedSequenceKey;
100471             }); // update viewfields if needed
100472
100473             context.container().selectAll('.layer-streetside-images .viewfield-group .viewfield').attr('d', viewfieldPath);
100474
100475             function viewfieldPath() {
100476               var d = this.parentNode.__data__;
100477
100478               if (d.pano && d.key !== selectedBubbleKey) {
100479                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
100480               } else {
100481                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
100482               }
100483             }
100484
100485             return this;
100486           },
100487           updateUrlImage: function updateUrlImage(imageKey) {
100488             if (!window.mocha) {
100489               var hash = utilStringQs(window.location.hash);
100490
100491               if (imageKey) {
100492                 hash.photo = 'streetside/' + imageKey;
100493               } else {
100494                 delete hash.photo;
100495               }
100496
100497               window.location.replace('#' + utilQsString(hash, true));
100498             }
100499           },
100500
100501           /**
100502            * cache().
100503            */
100504           cache: function cache() {
100505             return _ssCache;
100506           }
100507         };
100508
100509         var _apibase = 'https://taginfo.openstreetmap.org/api/4/';
100510         var _inflight = {};
100511         var _popularKeys = {};
100512         var _taginfoCache = {};
100513         var tag_sorts = {
100514           point: 'count_nodes',
100515           vertex: 'count_nodes',
100516           area: 'count_ways',
100517           line: 'count_ways'
100518         };
100519         var tag_sort_members = {
100520           point: 'count_node_members',
100521           vertex: 'count_node_members',
100522           area: 'count_way_members',
100523           line: 'count_way_members',
100524           relation: 'count_relation_members'
100525         };
100526         var tag_filters = {
100527           point: 'nodes',
100528           vertex: 'nodes',
100529           area: 'ways',
100530           line: 'ways'
100531         };
100532         var tag_members_fractions = {
100533           point: 'count_node_members_fraction',
100534           vertex: 'count_node_members_fraction',
100535           area: 'count_way_members_fraction',
100536           line: 'count_way_members_fraction',
100537           relation: 'count_relation_members_fraction'
100538         };
100539
100540         function sets(params, n, o) {
100541           if (params.geometry && o[params.geometry]) {
100542             params[n] = o[params.geometry];
100543           }
100544
100545           return params;
100546         }
100547
100548         function setFilter(params) {
100549           return sets(params, 'filter', tag_filters);
100550         }
100551
100552         function setSort(params) {
100553           return sets(params, 'sortname', tag_sorts);
100554         }
100555
100556         function setSortMembers(params) {
100557           return sets(params, 'sortname', tag_sort_members);
100558         }
100559
100560         function clean(params) {
100561           return utilObjectOmit(params, ['geometry', 'debounce']);
100562         }
100563
100564         function filterKeys(type) {
100565           var count_type = type ? 'count_' + type : 'count_all';
100566           return function (d) {
100567             return parseFloat(d[count_type]) > 2500 || d.in_wiki;
100568           };
100569         }
100570
100571         function filterMultikeys(prefix) {
100572           return function (d) {
100573             // d.key begins with prefix, and d.key contains no additional ':'s
100574             var re = new RegExp('^' + prefix + '(.*)$');
100575             var matches = d.key.match(re) || [];
100576             return matches.length === 2 && matches[1].indexOf(':') === -1;
100577           };
100578         }
100579
100580         function filterValues(allowUpperCase) {
100581           return function (d) {
100582             if (d.value.match(/[;,]/) !== null) return false; // exclude some punctuation
100583
100584             if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false; // exclude uppercase letters
100585
100586             return parseFloat(d.fraction) > 0.0;
100587           };
100588         }
100589
100590         function filterRoles(geometry) {
100591           return function (d) {
100592             if (d.role === '') return false; // exclude empty role
100593
100594             if (d.role.match(/[A-Z*;,]/) !== null) return false; // exclude uppercase letters and some punctuation
100595
100596             return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
100597           };
100598         }
100599
100600         function valKey(d) {
100601           return {
100602             value: d.key,
100603             title: d.key
100604           };
100605         }
100606
100607         function valKeyDescription(d) {
100608           var obj = {
100609             value: d.value,
100610             title: d.description || d.value
100611           };
100612
100613           if (d.count) {
100614             obj.count = d.count;
100615           }
100616
100617           return obj;
100618         }
100619
100620         function roleKey(d) {
100621           return {
100622             value: d.role,
100623             title: d.role
100624           };
100625         } // sort keys with ':' lower than keys without ':'
100626
100627
100628         function sortKeys(a, b) {
100629           return a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1 ? -1 : a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1 ? 1 : 0;
100630         }
100631
100632         var debouncedRequest = debounce(request, 300, {
100633           leading: false
100634         });
100635
100636         function request(url, params, exactMatch, callback, loaded) {
100637           if (_inflight[url]) return;
100638           if (checkCache(url, params, exactMatch, callback)) return;
100639           var controller = new AbortController();
100640           _inflight[url] = controller;
100641           d3_json(url, {
100642             signal: controller.signal
100643           }).then(function (result) {
100644             delete _inflight[url];
100645             if (loaded) loaded(null, result);
100646           })["catch"](function (err) {
100647             delete _inflight[url];
100648             if (err.name === 'AbortError') return;
100649             if (loaded) loaded(err.message);
100650           });
100651         }
100652
100653         function checkCache(url, params, exactMatch, callback) {
100654           var rp = params.rp || 25;
100655           var testQuery = params.query || '';
100656           var testUrl = url;
100657
100658           do {
100659             var hit = _taginfoCache[testUrl]; // exact match, or shorter match yielding fewer than max results (rp)
100660
100661             if (hit && (url === testUrl || hit.length < rp)) {
100662               callback(null, hit);
100663               return true;
100664             } // don't try to shorten the query
100665
100666
100667             if (exactMatch || !testQuery.length) return false; // do shorten the query to see if we already have a cached result
100668             // that has returned fewer than max results (rp)
100669
100670             testQuery = testQuery.slice(0, -1);
100671             testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
100672           } while (testQuery.length >= 0);
100673
100674           return false;
100675         }
100676
100677         var serviceTaginfo = {
100678           init: function init() {
100679             _inflight = {};
100680             _taginfoCache = {};
100681             _popularKeys = {
100682               // manually exclude some keys – #5377, #7485
100683               postal_code: true,
100684               full_name: true,
100685               loc_name: true,
100686               reg_name: true,
100687               short_name: true,
100688               sorting_name: true,
100689               artist_name: true,
100690               nat_name: true,
100691               long_name: true,
100692               'bridge:name': true
100693             }; // Fetch popular keys.  We'll exclude these from `values`
100694             // lookups because they stress taginfo, and they aren't likely
100695             // to yield meaningful autocomplete results.. see #3955
100696
100697             var params = {
100698               rp: 100,
100699               sortname: 'values_all',
100700               sortorder: 'desc',
100701               page: 1,
100702               debounce: false,
100703               lang: _mainLocalizer.languageCode()
100704             };
100705             this.keys(params, function (err, data) {
100706               if (err) return;
100707               data.forEach(function (d) {
100708                 if (d.value === 'opening_hours') return; // exception
100709
100710                 _popularKeys[d.value] = true;
100711               });
100712             });
100713           },
100714           reset: function reset() {
100715             Object.values(_inflight).forEach(function (controller) {
100716               controller.abort();
100717             });
100718             _inflight = {};
100719           },
100720           keys: function keys(params, callback) {
100721             var doRequest = params.debounce ? debouncedRequest : request;
100722             params = clean(setSort(params));
100723             params = Object.assign({
100724               rp: 10,
100725               sortname: 'count_all',
100726               sortorder: 'desc',
100727               page: 1,
100728               lang: _mainLocalizer.languageCode()
100729             }, params);
100730             var url = _apibase + 'keys/all?' + utilQsString(params);
100731             doRequest(url, params, false, callback, function (err, d) {
100732               if (err) {
100733                 callback(err);
100734               } else {
100735                 var f = filterKeys(params.filter);
100736                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
100737                 _taginfoCache[url] = result;
100738                 callback(null, result);
100739               }
100740             });
100741           },
100742           multikeys: function multikeys(params, callback) {
100743             var doRequest = params.debounce ? debouncedRequest : request;
100744             params = clean(setSort(params));
100745             params = Object.assign({
100746               rp: 25,
100747               sortname: 'count_all',
100748               sortorder: 'desc',
100749               page: 1,
100750               lang: _mainLocalizer.languageCode()
100751             }, params);
100752             var prefix = params.query;
100753             var url = _apibase + 'keys/all?' + utilQsString(params);
100754             doRequest(url, params, true, callback, function (err, d) {
100755               if (err) {
100756                 callback(err);
100757               } else {
100758                 var f = filterMultikeys(prefix);
100759                 var result = d.data.filter(f).map(valKey);
100760                 _taginfoCache[url] = result;
100761                 callback(null, result);
100762               }
100763             });
100764           },
100765           values: function values(params, callback) {
100766             // Exclude popular keys from values lookups.. see #3955
100767             var key = params.key;
100768
100769             if (key && _popularKeys[key]) {
100770               callback(null, []);
100771               return;
100772             }
100773
100774             var doRequest = params.debounce ? debouncedRequest : request;
100775             params = clean(setSort(setFilter(params)));
100776             params = Object.assign({
100777               rp: 25,
100778               sortname: 'count_all',
100779               sortorder: 'desc',
100780               page: 1,
100781               lang: _mainLocalizer.languageCode()
100782             }, params);
100783             var url = _apibase + 'key/values?' + utilQsString(params);
100784             doRequest(url, params, false, callback, function (err, d) {
100785               if (err) {
100786                 callback(err);
100787               } else {
100788                 // In most cases we prefer taginfo value results with lowercase letters.
100789                 // A few OSM keys expect values to contain uppercase values (see #3377).
100790                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
100791                 // but these are the fields where taginfo value lookup is most useful.
100792                 var re = /network|taxon|genus|species|brand|grape_variety|royal_cypher|listed_status|booth|rating|stars|:output|_hours|_times|_ref|manufacturer|country|target|brewery/;
100793                 var allowUpperCase = re.test(params.key);
100794                 var f = filterValues(allowUpperCase);
100795                 var result = d.data.filter(f).map(valKeyDescription);
100796                 _taginfoCache[url] = result;
100797                 callback(null, result);
100798               }
100799             });
100800           },
100801           roles: function roles(params, callback) {
100802             var doRequest = params.debounce ? debouncedRequest : request;
100803             var geometry = params.geometry;
100804             params = clean(setSortMembers(params));
100805             params = Object.assign({
100806               rp: 25,
100807               sortname: 'count_all_members',
100808               sortorder: 'desc',
100809               page: 1,
100810               lang: _mainLocalizer.languageCode()
100811             }, params);
100812             var url = _apibase + 'relation/roles?' + utilQsString(params);
100813             doRequest(url, params, true, callback, function (err, d) {
100814               if (err) {
100815                 callback(err);
100816               } else {
100817                 var f = filterRoles(geometry);
100818                 var result = d.data.filter(f).map(roleKey);
100819                 _taginfoCache[url] = result;
100820                 callback(null, result);
100821               }
100822             });
100823           },
100824           docs: function docs(params, callback) {
100825             var doRequest = params.debounce ? debouncedRequest : request;
100826             params = clean(setSort(params));
100827             var path = 'key/wiki_pages?';
100828
100829             if (params.value) {
100830               path = 'tag/wiki_pages?';
100831             } else if (params.rtype) {
100832               path = 'relation/wiki_pages?';
100833             }
100834
100835             var url = _apibase + path + utilQsString(params);
100836             doRequest(url, params, true, callback, function (err, d) {
100837               if (err) {
100838                 callback(err);
100839               } else {
100840                 _taginfoCache[url] = d.data;
100841                 callback(null, d.data);
100842               }
100843             });
100844           },
100845           apibase: function apibase(_) {
100846             if (!arguments.length) return _apibase;
100847             _apibase = _;
100848             return this;
100849           }
100850         };
100851
100852         /**
100853          * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
100854          *
100855          * @name feature
100856          * @param {Geometry} geometry input geometry
100857          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100858          * @param {Object} [options={}] Optional Parameters
100859          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100860          * @param {string|number} [options.id] Identifier associated with the Feature
100861          * @returns {Feature} a GeoJSON Feature
100862          * @example
100863          * var geometry = {
100864          *   "type": "Point",
100865          *   "coordinates": [110, 50]
100866          * };
100867          *
100868          * var feature = turf.feature(geometry);
100869          *
100870          * //=feature
100871          */
100872
100873         function feature(geom, properties, options) {
100874           if (options === void 0) {
100875             options = {};
100876           }
100877
100878           var feat = {
100879             type: "Feature"
100880           };
100881
100882           if (options.id === 0 || options.id) {
100883             feat.id = options.id;
100884           }
100885
100886           if (options.bbox) {
100887             feat.bbox = options.bbox;
100888           }
100889
100890           feat.properties = properties || {};
100891           feat.geometry = geom;
100892           return feat;
100893         }
100894         /**
100895          * Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
100896          *
100897          * @name polygon
100898          * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
100899          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100900          * @param {Object} [options={}] Optional Parameters
100901          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100902          * @param {string|number} [options.id] Identifier associated with the Feature
100903          * @returns {Feature<Polygon>} Polygon Feature
100904          * @example
100905          * var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
100906          *
100907          * //=polygon
100908          */
100909
100910         function polygon(coordinates, properties, options) {
100911           if (options === void 0) {
100912             options = {};
100913           }
100914
100915           for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) {
100916             var ring = coordinates_1[_i];
100917
100918             if (ring.length < 4) {
100919               throw new Error("Each LinearRing of a Polygon must have 4 or more Positions.");
100920             }
100921
100922             for (var j = 0; j < ring[ring.length - 1].length; j++) {
100923               // Check if first point of Polygon contains two numbers
100924               if (ring[ring.length - 1][j] !== ring[0][j]) {
100925                 throw new Error("First and last Position are not equivalent.");
100926               }
100927             }
100928           }
100929
100930           var geom = {
100931             type: "Polygon",
100932             coordinates: coordinates
100933           };
100934           return feature(geom, properties, options);
100935         }
100936         /**
100937          * Creates a {@link LineString} {@link Feature} from an Array of Positions.
100938          *
100939          * @name lineString
100940          * @param {Array<Array<number>>} coordinates an array of Positions
100941          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100942          * @param {Object} [options={}] Optional Parameters
100943          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100944          * @param {string|number} [options.id] Identifier associated with the Feature
100945          * @returns {Feature<LineString>} LineString Feature
100946          * @example
100947          * var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
100948          * var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
100949          *
100950          * //=linestring1
100951          * //=linestring2
100952          */
100953
100954         function lineString(coordinates, properties, options) {
100955           if (options === void 0) {
100956             options = {};
100957           }
100958
100959           if (coordinates.length < 2) {
100960             throw new Error("coordinates must be an array of two or more positions");
100961           }
100962
100963           var geom = {
100964             type: "LineString",
100965             coordinates: coordinates
100966           };
100967           return feature(geom, properties, options);
100968         }
100969         /**
100970          * Creates a {@link Feature<MultiLineString>} based on a
100971          * coordinate array. Properties can be added optionally.
100972          *
100973          * @name multiLineString
100974          * @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
100975          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100976          * @param {Object} [options={}] Optional Parameters
100977          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100978          * @param {string|number} [options.id] Identifier associated with the Feature
100979          * @returns {Feature<MultiLineString>} a MultiLineString feature
100980          * @throws {Error} if no coordinates are passed
100981          * @example
100982          * var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
100983          *
100984          * //=multiLine
100985          */
100986
100987         function multiLineString(coordinates, properties, options) {
100988           if (options === void 0) {
100989             options = {};
100990           }
100991
100992           var geom = {
100993             type: "MultiLineString",
100994             coordinates: coordinates
100995           };
100996           return feature(geom, properties, options);
100997         }
100998         /**
100999          * Creates a {@link Feature<MultiPolygon>} based on a
101000          * coordinate array. Properties can be added optionally.
101001          *
101002          * @name multiPolygon
101003          * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
101004          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
101005          * @param {Object} [options={}] Optional Parameters
101006          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
101007          * @param {string|number} [options.id] Identifier associated with the Feature
101008          * @returns {Feature<MultiPolygon>} a multipolygon feature
101009          * @throws {Error} if no coordinates are passed
101010          * @example
101011          * var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
101012          *
101013          * //=multiPoly
101014          *
101015          */
101016
101017         function multiPolygon(coordinates, properties, options) {
101018           if (options === void 0) {
101019             options = {};
101020           }
101021
101022           var geom = {
101023             type: "MultiPolygon",
101024             coordinates: coordinates
101025           };
101026           return feature(geom, properties, options);
101027         }
101028
101029         /**
101030          * Get Geometry from Feature or Geometry Object
101031          *
101032          * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
101033          * @returns {Geometry|null} GeoJSON Geometry Object
101034          * @throws {Error} if geojson is not a Feature or Geometry Object
101035          * @example
101036          * var point = {
101037          *   "type": "Feature",
101038          *   "properties": {},
101039          *   "geometry": {
101040          *     "type": "Point",
101041          *     "coordinates": [110, 40]
101042          *   }
101043          * }
101044          * var geom = turf.getGeom(point)
101045          * //={"type": "Point", "coordinates": [110, 40]}
101046          */
101047
101048         function getGeom(geojson) {
101049           if (geojson.type === "Feature") {
101050             return geojson.geometry;
101051           }
101052
101053           return geojson;
101054         }
101055
101056         // Cohen-Sutherland line clipping algorithm, adapted to efficiently
101057         // handle polylines rather than just segments
101058         function lineclip(points, bbox, result) {
101059           var len = points.length,
101060               codeA = bitCode(points[0], bbox),
101061               part = [],
101062               i,
101063               codeB,
101064               lastCode;
101065           var a;
101066           var b;
101067           if (!result) result = [];
101068
101069           for (i = 1; i < len; i++) {
101070             a = points[i - 1];
101071             b = points[i];
101072             codeB = lastCode = bitCode(b, bbox);
101073
101074             while (true) {
101075               if (!(codeA | codeB)) {
101076                 // accept
101077                 part.push(a);
101078
101079                 if (codeB !== lastCode) {
101080                   // segment went outside
101081                   part.push(b);
101082
101083                   if (i < len - 1) {
101084                     // start a new line
101085                     result.push(part);
101086                     part = [];
101087                   }
101088                 } else if (i === len - 1) {
101089                   part.push(b);
101090                 }
101091
101092                 break;
101093               } else if (codeA & codeB) {
101094                 // trivial reject
101095                 break;
101096               } else if (codeA) {
101097                 // a outside, intersect with clip edge
101098                 a = intersect(a, b, codeA, bbox);
101099                 codeA = bitCode(a, bbox);
101100               } else {
101101                 // b outside
101102                 b = intersect(a, b, codeB, bbox);
101103                 codeB = bitCode(b, bbox);
101104               }
101105             }
101106
101107             codeA = lastCode;
101108           }
101109
101110           if (part.length) result.push(part);
101111           return result;
101112         } // Sutherland-Hodgeman polygon clipping algorithm
101113
101114         function polygonclip(points, bbox) {
101115           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
101116
101117           for (edge = 1; edge <= 8; edge *= 2) {
101118             result = [];
101119             prev = points[points.length - 1];
101120             prevInside = !(bitCode(prev, bbox) & edge);
101121
101122             for (i = 0; i < points.length; i++) {
101123               p = points[i];
101124               inside = !(bitCode(p, bbox) & edge); // if segment goes through the clip window, add an intersection
101125
101126               if (inside !== prevInside) result.push(intersect(prev, p, edge, bbox));
101127               if (inside) result.push(p); // add a point if it's inside
101128
101129               prev = p;
101130               prevInside = inside;
101131             }
101132
101133             points = result;
101134             if (!points.length) break;
101135           }
101136
101137           return result;
101138         } // intersect a segment against one of the 4 lines that make up the bbox
101139
101140         function intersect(a, b, edge, bbox) {
101141           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] // top
101142           : edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] // bottom
101143           : edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] // right
101144           : edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] // left
101145           : null;
101146         } // bit code reflects the point position relative to the bbox:
101147         //         left  mid  right
101148         //    top  1001  1000  1010
101149         //    mid  0001  0000  0010
101150         // bottom  0101  0100  0110
101151
101152
101153         function bitCode(p, bbox) {
101154           var code = 0;
101155           if (p[0] < bbox[0]) code |= 1; // left
101156           else if (p[0] > bbox[2]) code |= 2; // right
101157
101158           if (p[1] < bbox[1]) code |= 4; // bottom
101159           else if (p[1] > bbox[3]) code |= 8; // top
101160
101161           return code;
101162         }
101163
101164         /**
101165          * Takes a {@link Feature} and a bbox and clips the feature to the bbox using
101166          * [lineclip](https://github.com/mapbox/lineclip).
101167          * May result in degenerate edges when clipping Polygons.
101168          *
101169          * @name bboxClip
101170          * @param {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature feature to clip to the bbox
101171          * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
101172          * @returns {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} clipped Feature
101173          * @example
101174          * var bbox = [0, 0, 10, 10];
101175          * var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]);
101176          *
101177          * var clipped = turf.bboxClip(poly, bbox);
101178          *
101179          * //addToMap
101180          * var addToMap = [bbox, poly, clipped]
101181          */
101182
101183         function bboxClip(feature, bbox) {
101184           var geom = getGeom(feature);
101185           var type = geom.type;
101186           var properties = feature.type === "Feature" ? feature.properties : {};
101187           var coords = geom.coordinates;
101188
101189           switch (type) {
101190             case "LineString":
101191             case "MultiLineString":
101192               var lines_1 = [];
101193
101194               if (type === "LineString") {
101195                 coords = [coords];
101196               }
101197
101198               coords.forEach(function (line) {
101199                 lineclip(line, bbox, lines_1);
101200               });
101201
101202               if (lines_1.length === 1) {
101203                 return lineString(lines_1[0], properties);
101204               }
101205
101206               return multiLineString(lines_1, properties);
101207
101208             case "Polygon":
101209               return polygon(clipPolygon(coords, bbox), properties);
101210
101211             case "MultiPolygon":
101212               return multiPolygon(coords.map(function (poly) {
101213                 return clipPolygon(poly, bbox);
101214               }), properties);
101215
101216             default:
101217               throw new Error("geometry " + type + " not supported");
101218           }
101219         }
101220
101221         function clipPolygon(rings, bbox) {
101222           var outRings = [];
101223
101224           for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
101225             var ring = rings_1[_i];
101226             var clipped = polygonclip(ring, bbox);
101227
101228             if (clipped.length > 0) {
101229               if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
101230                 clipped.push(clipped[0]);
101231               }
101232
101233               if (clipped.length >= 4) {
101234                 outRings.push(clipped);
101235               }
101236             }
101237           }
101238
101239           return outRings;
101240         }
101241
101242         var tiler = utilTiler().tileSize(512).margin(1);
101243         var dispatch = dispatch$8('loadedData');
101244
101245         var _vtCache;
101246
101247         function abortRequest(controller) {
101248           controller.abort();
101249         }
101250
101251         function vtToGeoJSON(data, tile, mergeCache) {
101252           var vectorTile$1 = new vectorTile.VectorTile(new pbf(data));
101253           var layers = Object.keys(vectorTile$1.layers);
101254
101255           if (!Array.isArray(layers)) {
101256             layers = [layers];
101257           }
101258
101259           var features = [];
101260           layers.forEach(function (layerID) {
101261             var layer = vectorTile$1.layers[layerID];
101262
101263             if (layer) {
101264               for (var i = 0; i < layer.length; i++) {
101265                 var feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
101266                 var geometry = feature.geometry; // Treat all Polygons as MultiPolygons
101267
101268                 if (geometry.type === 'Polygon') {
101269                   geometry.type = 'MultiPolygon';
101270                   geometry.coordinates = [geometry.coordinates];
101271                 }
101272
101273                 var isClipped = false; // Clip to tile bounds
101274
101275                 if (geometry.type === 'MultiPolygon') {
101276                   var featureClip = bboxClip(feature, tile.extent.rectangle());
101277
101278                   if (!fastDeepEqual(feature.geometry, featureClip.geometry)) {
101279                     // feature = featureClip;
101280                     isClipped = true;
101281                   }
101282
101283                   if (!feature.geometry.coordinates.length) continue; // not actually on this tile
101284
101285                   if (!feature.geometry.coordinates[0].length) continue; // not actually on this tile
101286                 } // Generate some unique IDs and add some metadata
101287
101288
101289                 var featurehash = utilHashcode(fastJsonStableStringify(feature));
101290                 var propertyhash = utilHashcode(fastJsonStableStringify(feature.properties || {}));
101291                 feature.__layerID__ = layerID.replace(/[^_a-zA-Z0-9\-]/g, '_');
101292                 feature.__featurehash__ = featurehash;
101293                 feature.__propertyhash__ = propertyhash;
101294                 features.push(feature); // Clipped Polygons at same zoom with identical properties can get merged
101295
101296                 if (isClipped && geometry.type === 'MultiPolygon') {
101297                   var merged = mergeCache[propertyhash];
101298
101299                   if (merged && merged.length) {
101300                     var other = merged[0];
101301                     var coords = index.union(feature.geometry.coordinates, other.geometry.coordinates);
101302
101303                     if (!coords || !coords.length) {
101304                       continue; // something failed in polygon union
101305                     }
101306
101307                     merged.push(feature);
101308
101309                     for (var j = 0; j < merged.length; j++) {
101310                       // all these features get...
101311                       merged[j].geometry.coordinates = coords; // same coords
101312
101313                       merged[j].__featurehash__ = featurehash; // same hash, so deduplication works
101314                     }
101315                   } else {
101316                     mergeCache[propertyhash] = [feature];
101317                   }
101318                 }
101319               }
101320             }
101321           });
101322           return features;
101323         }
101324
101325         function loadTile(source, tile) {
101326           if (source.loaded[tile.id] || source.inflight[tile.id]) return;
101327           var url = source.template.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]) // TMS-flipped y coordinate
101328           .replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function (s, r) {
101329             var subdomains = r.split(',');
101330             return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
101331           });
101332           var controller = new AbortController();
101333           source.inflight[tile.id] = controller;
101334           fetch(url, {
101335             signal: controller.signal
101336           }).then(function (response) {
101337             if (!response.ok) {
101338               throw new Error(response.status + ' ' + response.statusText);
101339             }
101340
101341             source.loaded[tile.id] = [];
101342             delete source.inflight[tile.id];
101343             return response.arrayBuffer();
101344           }).then(function (data) {
101345             if (!data) {
101346               throw new Error('No Data');
101347             }
101348
101349             var z = tile.xyz[2];
101350
101351             if (!source.canMerge[z]) {
101352               source.canMerge[z] = {}; // initialize mergeCache
101353             }
101354
101355             source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z]);
101356             dispatch.call('loadedData');
101357           })["catch"](function () {
101358             source.loaded[tile.id] = [];
101359             delete source.inflight[tile.id];
101360           });
101361         }
101362
101363         var serviceVectorTile = {
101364           init: function init() {
101365             if (!_vtCache) {
101366               this.reset();
101367             }
101368
101369             this.event = utilRebind(this, dispatch, 'on');
101370           },
101371           reset: function reset() {
101372             for (var sourceID in _vtCache) {
101373               var source = _vtCache[sourceID];
101374
101375               if (source && source.inflight) {
101376                 Object.values(source.inflight).forEach(abortRequest);
101377               }
101378             }
101379
101380             _vtCache = {};
101381           },
101382           addSource: function addSource(sourceID, template) {
101383             _vtCache[sourceID] = {
101384               template: template,
101385               inflight: {},
101386               loaded: {},
101387               canMerge: {}
101388             };
101389             return _vtCache[sourceID];
101390           },
101391           data: function data(sourceID, projection) {
101392             var source = _vtCache[sourceID];
101393             if (!source) return [];
101394             var tiles = tiler.getTiles(projection);
101395             var seen = {};
101396             var results = [];
101397
101398             for (var i = 0; i < tiles.length; i++) {
101399               var features = source.loaded[tiles[i].id];
101400               if (!features || !features.length) continue;
101401
101402               for (var j = 0; j < features.length; j++) {
101403                 var feature = features[j];
101404                 var hash = feature.__featurehash__;
101405                 if (seen[hash]) continue;
101406                 seen[hash] = true; // return a shallow copy, because the hash may change
101407                 // later if this feature gets merged with another
101408
101409                 results.push(Object.assign({}, feature)); // shallow copy
101410               }
101411             }
101412
101413             return results;
101414           },
101415           loadTiles: function loadTiles(sourceID, template, projection) {
101416             var source = _vtCache[sourceID];
101417
101418             if (!source) {
101419               source = this.addSource(sourceID, template);
101420             }
101421
101422             var tiles = tiler.getTiles(projection); // abort inflight requests that are no longer needed
101423
101424             Object.keys(source.inflight).forEach(function (k) {
101425               var wanted = tiles.find(function (tile) {
101426                 return k === tile.id;
101427               });
101428
101429               if (!wanted) {
101430                 abortRequest(source.inflight[k]);
101431                 delete source.inflight[k];
101432               }
101433             });
101434             tiles.forEach(function (tile) {
101435               loadTile(source, tile);
101436             });
101437           },
101438           cache: function cache() {
101439             return _vtCache;
101440           }
101441         };
101442
101443         var apibase = 'https://www.wikidata.org/w/api.php?';
101444         var _wikidataCache = {};
101445         var serviceWikidata = {
101446           init: function init() {},
101447           reset: function reset() {
101448             _wikidataCache = {};
101449           },
101450           // Search for Wikidata items matching the query
101451           itemsForSearchQuery: function itemsForSearchQuery(query, callback) {
101452             if (!query) {
101453               if (callback) callback('No query', {});
101454               return;
101455             }
101456
101457             var lang = this.languagesToQuery()[0];
101458             var url = apibase + utilQsString({
101459               action: 'wbsearchentities',
101460               format: 'json',
101461               formatversion: 2,
101462               search: query,
101463               type: 'item',
101464               // the language to search
101465               language: lang,
101466               // the language for the label and description in the result
101467               uselang: lang,
101468               limit: 10,
101469               origin: '*'
101470             });
101471             d3_json(url).then(function (result) {
101472               if (result && result.error) {
101473                 throw new Error(result.error);
101474               }
101475
101476               if (callback) callback(null, result.search || {});
101477             })["catch"](function (err) {
101478               if (callback) callback(err.message, {});
101479             });
101480           },
101481           // Given a Wikipedia language and article title,
101482           // return an array of corresponding Wikidata entities.
101483           itemsByTitle: function itemsByTitle(lang, title, callback) {
101484             if (!title) {
101485               if (callback) callback('No title', {});
101486               return;
101487             }
101488
101489             lang = lang || 'en';
101490             var url = apibase + utilQsString({
101491               action: 'wbgetentities',
101492               format: 'json',
101493               formatversion: 2,
101494               sites: lang.replace(/-/g, '_') + 'wiki',
101495               titles: title,
101496               languages: 'en',
101497               // shrink response by filtering to one language
101498               origin: '*'
101499             });
101500             d3_json(url).then(function (result) {
101501               if (result && result.error) {
101502                 throw new Error(result.error);
101503               }
101504
101505               if (callback) callback(null, result.entities || {});
101506             })["catch"](function (err) {
101507               if (callback) callback(err.message, {});
101508             });
101509           },
101510           languagesToQuery: function languagesToQuery() {
101511             return _mainLocalizer.localeCodes().map(function (code) {
101512               return code.toLowerCase();
101513             }).filter(function (code) {
101514               // HACK: en-us isn't a wikidata language. We should really be filtering by
101515               // the languages known to be supported by wikidata.
101516               return code !== 'en-us';
101517             });
101518           },
101519           entityByQID: function entityByQID(qid, callback) {
101520             if (!qid) {
101521               callback('No qid', {});
101522               return;
101523             }
101524
101525             if (_wikidataCache[qid]) {
101526               if (callback) callback(null, _wikidataCache[qid]);
101527               return;
101528             }
101529
101530             var langs = this.languagesToQuery();
101531             var url = apibase + utilQsString({
101532               action: 'wbgetentities',
101533               format: 'json',
101534               formatversion: 2,
101535               ids: qid,
101536               props: 'labels|descriptions|claims|sitelinks',
101537               sitefilter: langs.map(function (d) {
101538                 return d + 'wiki';
101539               }).join('|'),
101540               languages: langs.join('|'),
101541               languagefallback: 1,
101542               origin: '*'
101543             });
101544             d3_json(url).then(function (result) {
101545               if (result && result.error) {
101546                 throw new Error(result.error);
101547               }
101548
101549               if (callback) callback(null, result.entities[qid] || {});
101550             })["catch"](function (err) {
101551               if (callback) callback(err.message, {});
101552             });
101553           },
101554           // Pass `params` object of the form:
101555           // {
101556           //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
101557           // }
101558           //
101559           // Get an result object used to display tag documentation
101560           // {
101561           //   title:        'string',
101562           //   description:  'string',
101563           //   editURL:      'string',
101564           //   imageURL:     'string',
101565           //   wiki:         { title: 'string', text: 'string', url: 'string' }
101566           // }
101567           //
101568           getDocs: function getDocs(params, callback) {
101569             var langs = this.languagesToQuery();
101570             this.entityByQID(params.qid, function (err, entity) {
101571               if (err || !entity) {
101572                 callback(err || 'No entity');
101573                 return;
101574               }
101575
101576               var i;
101577               var description;
101578
101579               for (i in langs) {
101580                 var code = langs[i];
101581
101582                 if (entity.descriptions[code] && entity.descriptions[code].language === code) {
101583                   description = entity.descriptions[code];
101584                   break;
101585                 }
101586               }
101587
101588               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
101589
101590               var result = {
101591                 title: entity.id,
101592                 description: description ? description.value : '',
101593                 descriptionLocaleCode: description ? description.language : '',
101594                 editURL: 'https://www.wikidata.org/wiki/' + entity.id
101595               }; // add image
101596
101597               if (entity.claims) {
101598                 var imageroot = 'https://commons.wikimedia.org/w/index.php';
101599                 var props = ['P154', 'P18']; // logo image, image
101600
101601                 var prop, image;
101602
101603                 for (i = 0; i < props.length; i++) {
101604                   prop = entity.claims[props[i]];
101605
101606                   if (prop && Object.keys(prop).length > 0) {
101607                     image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value;
101608
101609                     if (image) {
101610                       result.imageURL = imageroot + '?' + utilQsString({
101611                         title: 'Special:Redirect/file/' + image,
101612                         width: 400
101613                       });
101614                       break;
101615                     }
101616                   }
101617                 }
101618               }
101619
101620               if (entity.sitelinks) {
101621                 var englishLocale = _mainLocalizer.languageCode().toLowerCase() === 'en'; // must be one of these that we requested..
101622
101623                 for (i = 0; i < langs.length; i++) {
101624                   // check each, in order of preference
101625                   var w = langs[i] + 'wiki';
101626
101627                   if (entity.sitelinks[w]) {
101628                     var title = entity.sitelinks[w].title;
101629                     var tKey = 'inspector.wiki_reference';
101630
101631                     if (!englishLocale && langs[i] === 'en') {
101632                       // user's locale isn't English but
101633                       tKey = 'inspector.wiki_en_reference'; // we are sending them to enwiki anyway..
101634                     }
101635
101636                     result.wiki = {
101637                       title: title,
101638                       text: tKey,
101639                       url: 'https://' + langs[i] + '.wikipedia.org/wiki/' + title.replace(/ /g, '_')
101640                     };
101641                     break;
101642                   }
101643                 }
101644               }
101645
101646               callback(null, result);
101647             });
101648           }
101649         };
101650
101651         var endpoint = 'https://en.wikipedia.org/w/api.php?';
101652         var serviceWikipedia = {
101653           init: function init() {},
101654           reset: function reset() {},
101655           search: function search(lang, query, callback) {
101656             if (!query) {
101657               if (callback) callback('No Query', []);
101658               return;
101659             }
101660
101661             lang = lang || 'en';
101662             var url = endpoint.replace('en', lang) + utilQsString({
101663               action: 'query',
101664               list: 'search',
101665               srlimit: '10',
101666               srinfo: 'suggestion',
101667               format: 'json',
101668               origin: '*',
101669               srsearch: query
101670             });
101671             d3_json(url).then(function (result) {
101672               if (result && result.error) {
101673                 throw new Error(result.error);
101674               } else if (!result || !result.query || !result.query.search) {
101675                 throw new Error('No Results');
101676               }
101677
101678               if (callback) {
101679                 var titles = result.query.search.map(function (d) {
101680                   return d.title;
101681                 });
101682                 callback(null, titles);
101683               }
101684             })["catch"](function (err) {
101685               if (callback) callback(err, []);
101686             });
101687           },
101688           suggestions: function suggestions(lang, query, callback) {
101689             if (!query) {
101690               if (callback) callback('', []);
101691               return;
101692             }
101693
101694             lang = lang || 'en';
101695             var url = endpoint.replace('en', lang) + utilQsString({
101696               action: 'opensearch',
101697               namespace: 0,
101698               suggest: '',
101699               format: 'json',
101700               origin: '*',
101701               search: query
101702             });
101703             d3_json(url).then(function (result) {
101704               if (result && result.error) {
101705                 throw new Error(result.error);
101706               } else if (!result || result.length < 2) {
101707                 throw new Error('No Results');
101708               }
101709
101710               if (callback) callback(null, result[1] || []);
101711             })["catch"](function (err) {
101712               if (callback) callback(err.message, []);
101713             });
101714           },
101715           translations: function translations(lang, title, callback) {
101716             if (!title) {
101717               if (callback) callback('No Title');
101718               return;
101719             }
101720
101721             var url = endpoint.replace('en', lang) + utilQsString({
101722               action: 'query',
101723               prop: 'langlinks',
101724               format: 'json',
101725               origin: '*',
101726               lllimit: 500,
101727               titles: title
101728             });
101729             d3_json(url).then(function (result) {
101730               if (result && result.error) {
101731                 throw new Error(result.error);
101732               } else if (!result || !result.query || !result.query.pages) {
101733                 throw new Error('No Results');
101734               }
101735
101736               if (callback) {
101737                 var list = result.query.pages[Object.keys(result.query.pages)[0]];
101738                 var translations = {};
101739
101740                 if (list && list.langlinks) {
101741                   list.langlinks.forEach(function (d) {
101742                     translations[d.lang] = d['*'];
101743                   });
101744                 }
101745
101746                 callback(null, translations);
101747               }
101748             })["catch"](function (err) {
101749               if (callback) callback(err.message);
101750             });
101751           }
101752         };
101753
101754         var services = {
101755           geocoder: serviceNominatim,
101756           keepRight: serviceKeepRight,
101757           improveOSM: serviceImproveOSM,
101758           osmose: serviceOsmose,
101759           mapillary: serviceMapillary,
101760           nsi: serviceNsi,
101761           openstreetcam: serviceOpenstreetcam,
101762           osm: serviceOsm,
101763           osmWikibase: serviceOsmWikibase,
101764           maprules: serviceMapRules,
101765           streetside: serviceStreetside,
101766           taginfo: serviceTaginfo,
101767           vectorTile: serviceVectorTile,
101768           wikidata: serviceWikidata,
101769           wikipedia: serviceWikipedia
101770         };
101771
101772         function modeDragNote(context) {
101773           var mode = {
101774             id: 'drag-note',
101775             button: 'browse'
101776           };
101777           var edit = behaviorEdit(context);
101778
101779           var _nudgeInterval;
101780
101781           var _lastLoc;
101782
101783           var _note; // most current note.. dragged note may have stale datum.
101784
101785
101786           function startNudge(d3_event, nudge) {
101787             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
101788             _nudgeInterval = window.setInterval(function () {
101789               context.map().pan(nudge);
101790               doMove(d3_event, nudge);
101791             }, 50);
101792           }
101793
101794           function stopNudge() {
101795             if (_nudgeInterval) {
101796               window.clearInterval(_nudgeInterval);
101797               _nudgeInterval = null;
101798             }
101799           }
101800
101801           function origin(note) {
101802             return context.projection(note.loc);
101803           }
101804
101805           function start(d3_event, note) {
101806             _note = note;
101807             var osm = services.osm;
101808
101809             if (osm) {
101810               // Get latest note from cache.. The marker may have a stale datum bound to it
101811               // and dragging it around can sometimes delete the users note comment.
101812               _note = osm.getNote(_note.id);
101813             }
101814
101815             context.surface().selectAll('.note-' + _note.id).classed('active', true);
101816             context.perform(actionNoop());
101817             context.enter(mode);
101818             context.selectedNoteID(_note.id);
101819           }
101820
101821           function move(d3_event, entity, point) {
101822             d3_event.stopPropagation();
101823             _lastLoc = context.projection.invert(point);
101824             doMove(d3_event);
101825             var nudge = geoViewportEdge(point, context.map().dimensions());
101826
101827             if (nudge) {
101828               startNudge(d3_event, nudge);
101829             } else {
101830               stopNudge();
101831             }
101832           }
101833
101834           function doMove(d3_event, nudge) {
101835             nudge = nudge || [0, 0];
101836             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
101837             var currMouse = geoVecSubtract(currPoint, nudge);
101838             var loc = context.projection.invert(currMouse);
101839             _note = _note.move(loc);
101840             var osm = services.osm;
101841
101842             if (osm) {
101843               osm.replaceNote(_note); // update note cache
101844             }
101845
101846             context.replace(actionNoop()); // trigger redraw
101847           }
101848
101849           function end() {
101850             context.replace(actionNoop()); // trigger redraw
101851
101852             context.selectedNoteID(_note.id).enter(modeSelectNote(context, _note.id));
101853           }
101854
101855           var drag = behaviorDrag().selector('.layer-touch.markers .target.note.new').surface(context.container().select('.main-map').node()).origin(origin).on('start', start).on('move', move).on('end', end);
101856
101857           mode.enter = function () {
101858             context.install(edit);
101859           };
101860
101861           mode.exit = function () {
101862             context.ui().sidebar.hover.cancel();
101863             context.uninstall(edit);
101864             context.surface().selectAll('.active').classed('active', false);
101865             stopNudge();
101866           };
101867
101868           mode.behavior = drag;
101869           return mode;
101870         }
101871
101872         function modeSelectData(context, selectedDatum) {
101873           var mode = {
101874             id: 'select-data',
101875             button: 'browse'
101876           };
101877           var keybinding = utilKeybinding('select-data');
101878           var dataEditor = uiDataEditor(context);
101879           var behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior]; // class the data as selected, or return to browse mode if the data is gone
101880
101881           function selectData(d3_event, drawn) {
101882             var selection = context.surface().selectAll('.layer-mapdata .data' + selectedDatum.__featurehash__);
101883
101884             if (selection.empty()) {
101885               // Return to browse mode if selected DOM elements have
101886               // disappeared because the user moved them out of view..
101887               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
101888
101889               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
101890                 context.enter(modeBrowse(context));
101891               }
101892             } else {
101893               selection.classed('selected', true);
101894             }
101895           }
101896
101897           function esc() {
101898             if (context.container().select('.combobox').size()) return;
101899             context.enter(modeBrowse(context));
101900           }
101901
101902           mode.zoomToSelected = function () {
101903             var extent = geoExtent(d3_geoBounds(selectedDatum));
101904             context.map().centerZoomEase(extent.center(), context.map().trimmedExtentZoom(extent));
101905           };
101906
101907           mode.enter = function () {
101908             behaviors.forEach(context.install);
101909             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
101910             select(document).call(keybinding);
101911             selectData();
101912             var sidebar = context.ui().sidebar;
101913             sidebar.show(dataEditor.datum(selectedDatum)); // expand the sidebar, avoid obscuring the data if needed
101914
101915             var extent = geoExtent(d3_geoBounds(selectedDatum));
101916             sidebar.expand(sidebar.intersects(extent));
101917             context.map().on('drawn.select-data', selectData);
101918           };
101919
101920           mode.exit = function () {
101921             behaviors.forEach(context.uninstall);
101922             select(document).call(keybinding.unbind);
101923             context.surface().selectAll('.layer-mapdata .selected').classed('selected hover', false);
101924             context.map().on('drawn.select-data', null);
101925             context.ui().sidebar.hide();
101926           };
101927
101928           return mode;
101929         }
101930
101931         function behaviorSelect(context) {
101932           var _tolerancePx = 4; // see also behaviorDrag
101933
101934           var _lastMouseEvent = null;
101935           var _showMenu = false;
101936           var _downPointers = {};
101937           var _longPressTimeout = null;
101938           var _lastInteractionType = null; // the id of the down pointer that's enabling multiselection while down
101939
101940           var _multiselectionPointerId = null; // use pointer events on supported platforms; fallback to mouse events
101941
101942           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
101943
101944           function keydown(d3_event) {
101945             if (d3_event.keyCode === 32) {
101946               // don't react to spacebar events during text input
101947               var activeNode = document.activeElement;
101948               if (activeNode && new Set(['INPUT', 'TEXTAREA']).has(activeNode.nodeName)) return;
101949             }
101950
101951             if (d3_event.keyCode === 93 || // context menu key
101952             d3_event.keyCode === 32) {
101953               // spacebar
101954               d3_event.preventDefault();
101955             }
101956
101957             if (d3_event.repeat) return; // ignore repeated events for held keys
101958             // if any key is pressed the user is probably doing something other than long-pressing
101959
101960             cancelLongPress();
101961
101962             if (d3_event.shiftKey) {
101963               context.surface().classed('behavior-multiselect', true);
101964             }
101965
101966             if (d3_event.keyCode === 32) {
101967               // spacebar
101968               if (!_downPointers.spacebar && _lastMouseEvent) {
101969                 cancelLongPress();
101970                 _longPressTimeout = window.setTimeout(didLongPress, 500, 'spacebar', 'spacebar');
101971                 _downPointers.spacebar = {
101972                   firstEvent: _lastMouseEvent,
101973                   lastEvent: _lastMouseEvent
101974                 };
101975               }
101976             }
101977           }
101978
101979           function keyup(d3_event) {
101980             cancelLongPress();
101981
101982             if (!d3_event.shiftKey) {
101983               context.surface().classed('behavior-multiselect', false);
101984             }
101985
101986             if (d3_event.keyCode === 93) {
101987               // context menu key
101988               d3_event.preventDefault();
101989               _lastInteractionType = 'menukey';
101990               contextmenu(d3_event);
101991             } else if (d3_event.keyCode === 32) {
101992               // spacebar
101993               var pointer = _downPointers.spacebar;
101994
101995               if (pointer) {
101996                 delete _downPointers.spacebar;
101997                 if (pointer.done) return;
101998                 d3_event.preventDefault();
101999                 _lastInteractionType = 'spacebar';
102000                 click(pointer.firstEvent, pointer.lastEvent, 'spacebar');
102001               }
102002             }
102003           }
102004
102005           function pointerdown(d3_event) {
102006             var id = (d3_event.pointerId || 'mouse').toString();
102007             cancelLongPress();
102008             if (d3_event.buttons && d3_event.buttons !== 1) return;
102009             context.ui().closeEditMenu();
102010             _longPressTimeout = window.setTimeout(didLongPress, 500, id, 'longdown-' + (d3_event.pointerType || 'mouse'));
102011             _downPointers[id] = {
102012               firstEvent: d3_event,
102013               lastEvent: d3_event
102014             };
102015           }
102016
102017           function didLongPress(id, interactionType) {
102018             var pointer = _downPointers[id];
102019             if (!pointer) return;
102020
102021             for (var i in _downPointers) {
102022               // don't allow this or any currently down pointer to trigger another click
102023               _downPointers[i].done = true;
102024             } // treat long presses like right-clicks
102025
102026
102027             _longPressTimeout = null;
102028             _lastInteractionType = interactionType;
102029             _showMenu = true;
102030             click(pointer.firstEvent, pointer.lastEvent, id);
102031           }
102032
102033           function pointermove(d3_event) {
102034             var id = (d3_event.pointerId || 'mouse').toString();
102035
102036             if (_downPointers[id]) {
102037               _downPointers[id].lastEvent = d3_event;
102038             }
102039
102040             if (!d3_event.pointerType || d3_event.pointerType === 'mouse') {
102041               _lastMouseEvent = d3_event;
102042
102043               if (_downPointers.spacebar) {
102044                 _downPointers.spacebar.lastEvent = d3_event;
102045               }
102046             }
102047           }
102048
102049           function pointerup(d3_event) {
102050             var id = (d3_event.pointerId || 'mouse').toString();
102051             var pointer = _downPointers[id];
102052             if (!pointer) return;
102053             delete _downPointers[id];
102054
102055             if (_multiselectionPointerId === id) {
102056               _multiselectionPointerId = null;
102057             }
102058
102059             if (pointer.done) return;
102060             click(pointer.firstEvent, d3_event, id);
102061           }
102062
102063           function pointercancel(d3_event) {
102064             var id = (d3_event.pointerId || 'mouse').toString();
102065             if (!_downPointers[id]) return;
102066             delete _downPointers[id];
102067
102068             if (_multiselectionPointerId === id) {
102069               _multiselectionPointerId = null;
102070             }
102071           }
102072
102073           function contextmenu(d3_event) {
102074             d3_event.preventDefault();
102075
102076             if (!+d3_event.clientX && !+d3_event.clientY) {
102077               if (_lastMouseEvent) {
102078                 d3_event.sourceEvent = _lastMouseEvent;
102079               } else {
102080                 return;
102081               }
102082             } else {
102083               _lastMouseEvent = d3_event;
102084               _lastInteractionType = 'rightclick';
102085             }
102086
102087             _showMenu = true;
102088             click(d3_event, d3_event);
102089           }
102090
102091           function click(firstEvent, lastEvent, pointerId) {
102092             cancelLongPress();
102093             var mapNode = context.container().select('.main-map').node(); // Use the `main-map` coordinate system since the surface and supersurface
102094             // are transformed when drag-panning.
102095
102096             var pointGetter = utilFastMouse(mapNode);
102097             var p1 = pointGetter(firstEvent);
102098             var p2 = pointGetter(lastEvent);
102099             var dist = geoVecLength(p1, p2);
102100
102101             if (dist > _tolerancePx || !mapContains(lastEvent)) {
102102               resetProperties();
102103               return;
102104             }
102105
102106             var targetDatum = lastEvent.target.__data__;
102107             var multiselectEntityId;
102108
102109             if (!_multiselectionPointerId) {
102110               // If a different pointer than the one triggering this click is down on a
102111               // feature, treat this and all future clicks as multiselection until that
102112               // pointer is raised.
102113               var selectPointerInfo = pointerDownOnSelection(pointerId);
102114
102115               if (selectPointerInfo) {
102116                 _multiselectionPointerId = selectPointerInfo.pointerId; // if the other feature isn't selected yet, make sure we select it
102117
102118                 multiselectEntityId = !selectPointerInfo.selected && selectPointerInfo.entityId;
102119                 _downPointers[selectPointerInfo.pointerId].done = true;
102120               }
102121             } // support multiselect if data is already selected
102122
102123
102124             var isMultiselect = context.mode().id === 'select' && ( // and shift key is down
102125             lastEvent && lastEvent.shiftKey || // or we're lasso-selecting
102126             context.surface().select('.lasso').node() || // or a pointer is down over a selected feature
102127             _multiselectionPointerId && !multiselectEntityId);
102128
102129             processClick(targetDatum, isMultiselect, p2, multiselectEntityId);
102130
102131             function mapContains(event) {
102132               var rect = mapNode.getBoundingClientRect();
102133               return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
102134             }
102135
102136             function pointerDownOnSelection(skipPointerId) {
102137               var mode = context.mode();
102138               var selectedIDs = mode.id === 'select' ? mode.selectedIDs() : [];
102139
102140               for (var pointerId in _downPointers) {
102141                 if (pointerId === 'spacebar' || pointerId === skipPointerId) continue;
102142                 var pointerInfo = _downPointers[pointerId];
102143                 var p1 = pointGetter(pointerInfo.firstEvent);
102144                 var p2 = pointGetter(pointerInfo.lastEvent);
102145                 if (geoVecLength(p1, p2) > _tolerancePx) continue;
102146                 var datum = pointerInfo.firstEvent.target.__data__;
102147                 var entity = datum && datum.properties && datum.properties.entity || datum;
102148
102149                 if (context.graph().hasEntity(entity.id)) {
102150                   return {
102151                     pointerId: pointerId,
102152                     entityId: entity.id,
102153                     selected: selectedIDs.indexOf(entity.id) !== -1
102154                   };
102155                 }
102156               }
102157
102158               return null;
102159             }
102160           }
102161
102162           function processClick(datum, isMultiselect, point, alsoSelectId) {
102163             var mode = context.mode();
102164             var showMenu = _showMenu;
102165             var interactionType = _lastInteractionType;
102166             var entity = datum && datum.properties && datum.properties.entity;
102167             if (entity) datum = entity;
102168
102169             if (datum && datum.type === 'midpoint') {
102170               // treat targeting midpoints as if targeting the parent way
102171               datum = datum.parents[0];
102172             }
102173
102174             var newMode;
102175
102176             if (datum instanceof osmEntity) {
102177               // targeting an entity
102178               var selectedIDs = context.selectedIDs();
102179               context.selectedNoteID(null);
102180               context.selectedErrorID(null);
102181
102182               if (!isMultiselect) {
102183                 // don't change the selection if we're toggling the menu atop a multiselection
102184                 if (!showMenu || selectedIDs.length <= 1 || selectedIDs.indexOf(datum.id) === -1) {
102185                   if (alsoSelectId === datum.id) alsoSelectId = null;
102186                   selectedIDs = (alsoSelectId ? [alsoSelectId] : []).concat([datum.id]); // always enter modeSelect even if the entity is already
102187                   // selected since listeners may expect `context.enter` events,
102188                   // e.g. in the walkthrough
102189
102190                   newMode = mode.id === 'select' ? mode.selectedIDs(selectedIDs) : modeSelect(context, selectedIDs).selectBehavior(behavior);
102191                   context.enter(newMode);
102192                 }
102193               } else {
102194                 if (selectedIDs.indexOf(datum.id) !== -1) {
102195                   // clicked entity is already in the selectedIDs list..
102196                   if (!showMenu) {
102197                     // deselect clicked entity, then reenter select mode or return to browse mode..
102198                     selectedIDs = selectedIDs.filter(function (id) {
102199                       return id !== datum.id;
102200                     });
102201                     newMode = selectedIDs.length ? mode.selectedIDs(selectedIDs) : modeBrowse(context).selectBehavior(behavior);
102202                     context.enter(newMode);
102203                   }
102204                 } else {
102205                   // clicked entity is not in the selected list, add it..
102206                   selectedIDs = selectedIDs.concat([datum.id]);
102207                   newMode = mode.selectedIDs(selectedIDs);
102208                   context.enter(newMode);
102209                 }
102210               }
102211             } else if (datum && datum.__featurehash__ && !isMultiselect) {
102212               // targeting custom data
102213               context.selectedNoteID(null).enter(modeSelectData(context, datum));
102214             } else if (datum instanceof osmNote && !isMultiselect) {
102215               // targeting a note
102216               context.selectedNoteID(datum.id).enter(modeSelectNote(context, datum.id));
102217             } else if (datum instanceof QAItem & !isMultiselect) {
102218               // targeting an external QA issue
102219               context.selectedErrorID(datum.id).enter(modeSelectError(context, datum.id, datum.service));
102220             } else {
102221               // targeting nothing
102222               context.selectedNoteID(null);
102223               context.selectedErrorID(null);
102224
102225               if (!isMultiselect && mode.id !== 'browse') {
102226                 context.enter(modeBrowse(context));
102227               }
102228             }
102229
102230             context.ui().closeEditMenu(); // always request to show the edit menu in case the mode needs it
102231
102232             if (showMenu) context.ui().showEditMenu(point, interactionType);
102233             resetProperties();
102234           }
102235
102236           function cancelLongPress() {
102237             if (_longPressTimeout) window.clearTimeout(_longPressTimeout);
102238             _longPressTimeout = null;
102239           }
102240
102241           function resetProperties() {
102242             cancelLongPress();
102243             _showMenu = false;
102244             _lastInteractionType = null; // don't reset _lastMouseEvent since it might still be useful
102245           }
102246
102247           function behavior(selection) {
102248             resetProperties();
102249             _lastMouseEvent = context.map().lastPointerEvent();
102250             select(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) {
102251               // Edge and IE really like to show the contextmenu on the
102252               // menubar when user presses a keyboard menu button
102253               // even after we've already preventdefaulted the key event.
102254               var e = d3_event;
102255
102256               if (+e.clientX === 0 && +e.clientY === 0) {
102257                 d3_event.preventDefault();
102258               }
102259             });
102260             selection.on(_pointerPrefix + 'down.select', pointerdown).on('contextmenu.select', contextmenu);
102261             /*if (d3_event && d3_event.shiftKey) {
102262                 context.surface()
102263                     .classed('behavior-multiselect', true);
102264             }*/
102265           }
102266
102267           behavior.off = function (selection) {
102268             cancelLongPress();
102269             select(window).on('keydown.select', null).on('keyup.select', null).on('contextmenu.select-window', null).on(_pointerPrefix + 'move.select', null, true).on(_pointerPrefix + 'up.select', null, true).on('pointercancel.select', null, true);
102270             selection.on(_pointerPrefix + 'down.select', null).on('contextmenu.select', null);
102271             context.surface().classed('behavior-multiselect', false);
102272           };
102273
102274           return behavior;
102275         }
102276
102277         function operationContinue(context, selectedIDs) {
102278           var _entities = selectedIDs.map(function (id) {
102279             return context.graph().entity(id);
102280           });
102281
102282           var _geometries = Object.assign({
102283             line: [],
102284             vertex: []
102285           }, utilArrayGroupBy(_entities, function (entity) {
102286             return entity.geometry(context.graph());
102287           }));
102288
102289           var _vertex = _geometries.vertex.length && _geometries.vertex[0];
102290
102291           function candidateWays() {
102292             return _vertex ? context.graph().parentWays(_vertex).filter(function (parent) {
102293               return parent.geometry(context.graph()) === 'line' && !parent.isClosed() && parent.affix(_vertex.id) && (_geometries.line.length === 0 || _geometries.line[0] === parent);
102294             }) : [];
102295           }
102296
102297           var _candidates = candidateWays();
102298
102299           var operation = function operation() {
102300             var candidate = _candidates[0];
102301             context.enter(modeDrawLine(context, candidate.id, context.graph(), 'line', candidate.affix(_vertex.id), true));
102302           };
102303
102304           operation.relatedEntityIds = function () {
102305             return _candidates.length ? [_candidates[0].id] : [];
102306           };
102307
102308           operation.available = function () {
102309             return _geometries.vertex.length === 1 && _geometries.line.length <= 1 && !context.features().hasHiddenConnections(_vertex, context.graph());
102310           };
102311
102312           operation.disabled = function () {
102313             if (_candidates.length === 0) {
102314               return 'not_eligible';
102315             } else if (_candidates.length > 1) {
102316               return 'multiple';
102317             }
102318
102319             return false;
102320           };
102321
102322           operation.tooltip = function () {
102323             var disable = operation.disabled();
102324             return disable ? _t('operations.continue.' + disable) : _t('operations.continue.description');
102325           };
102326
102327           operation.annotation = function () {
102328             return _t('operations.continue.annotation.line');
102329           };
102330
102331           operation.id = 'continue';
102332           operation.keys = [_t('operations.continue.key')];
102333           operation.title = _t('operations.continue.title');
102334           operation.behavior = behaviorOperation(context).which(operation);
102335           return operation;
102336         }
102337
102338         function operationCopy(context, selectedIDs) {
102339           function getFilteredIdsToCopy() {
102340             return selectedIDs.filter(function (selectedID) {
102341               var entity = context.graph().hasEntity(selectedID); // don't copy untagged vertices separately from ways
102342
102343               return entity.hasInterestingTags() || entity.geometry(context.graph()) !== 'vertex';
102344             });
102345           }
102346
102347           var operation = function operation() {
102348             var graph = context.graph();
102349             var selected = groupEntities(getFilteredIdsToCopy(), graph);
102350             var canCopy = [];
102351             var skip = {};
102352             var entity;
102353             var i;
102354
102355             for (i = 0; i < selected.relation.length; i++) {
102356               entity = selected.relation[i];
102357
102358               if (!skip[entity.id] && entity.isComplete(graph)) {
102359                 canCopy.push(entity.id);
102360                 skip = getDescendants(entity.id, graph, skip);
102361               }
102362             }
102363
102364             for (i = 0; i < selected.way.length; i++) {
102365               entity = selected.way[i];
102366
102367               if (!skip[entity.id]) {
102368                 canCopy.push(entity.id);
102369                 skip = getDescendants(entity.id, graph, skip);
102370               }
102371             }
102372
102373             for (i = 0; i < selected.node.length; i++) {
102374               entity = selected.node[i];
102375
102376               if (!skip[entity.id]) {
102377                 canCopy.push(entity.id);
102378               }
102379             }
102380
102381             context.copyIDs(canCopy);
102382
102383             if (_point && (canCopy.length !== 1 || graph.entity(canCopy[0]).type !== 'node')) {
102384               // store the anchor coordinates if copying more than a single node
102385               context.copyLonLat(context.projection.invert(_point));
102386             } else {
102387               context.copyLonLat(null);
102388             }
102389           };
102390
102391           function groupEntities(ids, graph) {
102392             var entities = ids.map(function (id) {
102393               return graph.entity(id);
102394             });
102395             return Object.assign({
102396               relation: [],
102397               way: [],
102398               node: []
102399             }, utilArrayGroupBy(entities, 'type'));
102400           }
102401
102402           function getDescendants(id, graph, descendants) {
102403             var entity = graph.entity(id);
102404             var children;
102405             descendants = descendants || {};
102406
102407             if (entity.type === 'relation') {
102408               children = entity.members.map(function (m) {
102409                 return m.id;
102410               });
102411             } else if (entity.type === 'way') {
102412               children = entity.nodes;
102413             } else {
102414               children = [];
102415             }
102416
102417             for (var i = 0; i < children.length; i++) {
102418               if (!descendants[children[i]]) {
102419                 descendants[children[i]] = true;
102420                 descendants = getDescendants(children[i], graph, descendants);
102421               }
102422             }
102423
102424             return descendants;
102425           }
102426
102427           operation.available = function () {
102428             return getFilteredIdsToCopy().length > 0;
102429           };
102430
102431           operation.disabled = function () {
102432             var extent = utilTotalExtent(getFilteredIdsToCopy(), context.graph());
102433
102434             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
102435               return 'too_large';
102436             }
102437
102438             return false;
102439           };
102440
102441           operation.availableForKeypress = function () {
102442             var selection = window.getSelection && window.getSelection(); // if the user has text selected then let them copy that, not the selected feature
102443
102444             return !selection || !selection.toString();
102445           };
102446
102447           operation.tooltip = function () {
102448             var disable = operation.disabled();
102449             return disable ? _t('operations.copy.' + disable, {
102450               n: selectedIDs.length
102451             }) : _t('operations.copy.description', {
102452               n: selectedIDs.length
102453             });
102454           };
102455
102456           operation.annotation = function () {
102457             return _t('operations.copy.annotation', {
102458               n: selectedIDs.length
102459             });
102460           };
102461
102462           var _point;
102463
102464           operation.point = function (val) {
102465             _point = val;
102466             return operation;
102467           };
102468
102469           operation.id = 'copy';
102470           operation.keys = [uiCmd('⌘C')];
102471           operation.title = _t('operations.copy.title');
102472           operation.behavior = behaviorOperation(context).which(operation);
102473           return operation;
102474         }
102475
102476         function operationDisconnect(context, selectedIDs) {
102477           var _vertexIDs = [];
102478           var _wayIDs = [];
102479           var _otherIDs = [];
102480           var _actions = [];
102481           selectedIDs.forEach(function (id) {
102482             var entity = context.entity(id);
102483
102484             if (entity.type === 'way') {
102485               _wayIDs.push(id);
102486             } else if (entity.geometry(context.graph()) === 'vertex') {
102487               _vertexIDs.push(id);
102488             } else {
102489               _otherIDs.push(id);
102490             }
102491           });
102492
102493           var _coords,
102494               _descriptionID = '',
102495               _annotationID = 'features';
102496
102497           var _disconnectingVertexIds = [];
102498           var _disconnectingWayIds = [];
102499
102500           if (_vertexIDs.length > 0) {
102501             // At the selected vertices, disconnect the selected ways, if any, else
102502             // disconnect all connected ways
102503             _disconnectingVertexIds = _vertexIDs;
102504
102505             _vertexIDs.forEach(function (vertexID) {
102506               var action = actionDisconnect(vertexID);
102507
102508               if (_wayIDs.length > 0) {
102509                 var waysIDsForVertex = _wayIDs.filter(function (wayID) {
102510                   var way = context.entity(wayID);
102511                   return way.nodes.indexOf(vertexID) !== -1;
102512                 });
102513
102514                 action.limitWays(waysIDsForVertex);
102515               }
102516
102517               _actions.push(action);
102518
102519               _disconnectingWayIds = _disconnectingWayIds.concat(context.graph().parentWays(context.graph().entity(vertexID)).map(function (d) {
102520                 return d.id;
102521               }));
102522             });
102523
102524             _disconnectingWayIds = utilArrayUniq(_disconnectingWayIds).filter(function (id) {
102525               return _wayIDs.indexOf(id) === -1;
102526             });
102527             _descriptionID += _actions.length === 1 ? 'single_point.' : 'multiple_points.';
102528
102529             if (_wayIDs.length === 1) {
102530               _descriptionID += 'single_way.' + context.graph().geometry(_wayIDs[0]);
102531             } else {
102532               _descriptionID += _wayIDs.length === 0 ? 'no_ways' : 'multiple_ways';
102533             }
102534           } else if (_wayIDs.length > 0) {
102535             // Disconnect the selected ways from each other, if they're connected,
102536             // else disconnect them from all connected ways
102537             var ways = _wayIDs.map(function (id) {
102538               return context.entity(id);
102539             });
102540
102541             var nodes = utilGetAllNodes(_wayIDs, context.graph());
102542             _coords = nodes.map(function (n) {
102543               return n.loc;
102544             }); // actions for connected nodes shared by at least two selected ways
102545
102546             var sharedActions = [];
102547             var sharedNodes = []; // actions for connected nodes
102548
102549             var unsharedActions = [];
102550             var unsharedNodes = [];
102551             nodes.forEach(function (node) {
102552               var action = actionDisconnect(node.id).limitWays(_wayIDs);
102553
102554               if (action.disabled(context.graph()) !== 'not_connected') {
102555                 var count = 0;
102556
102557                 for (var i in ways) {
102558                   var way = ways[i];
102559
102560                   if (way.nodes.indexOf(node.id) !== -1) {
102561                     count += 1;
102562                   }
102563
102564                   if (count > 1) break;
102565                 }
102566
102567                 if (count > 1) {
102568                   sharedActions.push(action);
102569                   sharedNodes.push(node);
102570                 } else {
102571                   unsharedActions.push(action);
102572                   unsharedNodes.push(node);
102573                 }
102574               }
102575             });
102576             _descriptionID += 'no_points.';
102577             _descriptionID += _wayIDs.length === 1 ? 'single_way.' : 'multiple_ways.';
102578
102579             if (sharedActions.length) {
102580               // if any nodes are shared, only disconnect the selected ways from each other
102581               _actions = sharedActions;
102582               _disconnectingVertexIds = sharedNodes.map(function (node) {
102583                 return node.id;
102584               });
102585               _descriptionID += 'conjoined';
102586               _annotationID = 'from_each_other';
102587             } else {
102588               // if no nodes are shared, disconnect the selected ways from all connected ways
102589               _actions = unsharedActions;
102590               _disconnectingVertexIds = unsharedNodes.map(function (node) {
102591                 return node.id;
102592               });
102593
102594               if (_wayIDs.length === 1) {
102595                 _descriptionID += context.graph().geometry(_wayIDs[0]);
102596               } else {
102597                 _descriptionID += 'separate';
102598               }
102599             }
102600           }
102601
102602           var _extent = utilTotalExtent(_disconnectingVertexIds, context.graph());
102603
102604           var operation = function operation() {
102605             context.perform(function (graph) {
102606               return _actions.reduce(function (graph, action) {
102607                 return action(graph);
102608               }, graph);
102609             }, operation.annotation());
102610             context.validator().validate();
102611           };
102612
102613           operation.relatedEntityIds = function () {
102614             if (_vertexIDs.length) {
102615               return _disconnectingWayIds;
102616             }
102617
102618             return _disconnectingVertexIds;
102619           };
102620
102621           operation.available = function () {
102622             if (_actions.length === 0) return false;
102623             if (_otherIDs.length !== 0) return false;
102624             if (_vertexIDs.length !== 0 && _wayIDs.length !== 0 && !_wayIDs.every(function (wayID) {
102625               return _vertexIDs.some(function (vertexID) {
102626                 var way = context.entity(wayID);
102627                 return way.nodes.indexOf(vertexID) !== -1;
102628               });
102629             })) return false;
102630             return true;
102631           };
102632
102633           operation.disabled = function () {
102634             var reason;
102635
102636             for (var actionIndex in _actions) {
102637               reason = _actions[actionIndex].disabled(context.graph());
102638               if (reason) return reason;
102639             }
102640
102641             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
102642               return 'too_large.' + ((_vertexIDs.length ? _vertexIDs : _wayIDs).length === 1 ? 'single' : 'multiple');
102643             } else if (_coords && someMissing()) {
102644               return 'not_downloaded';
102645             } else if (selectedIDs.some(context.hasHiddenConnections)) {
102646               return 'connected_to_hidden';
102647             }
102648
102649             return false;
102650
102651             function someMissing() {
102652               if (context.inIntro()) return false;
102653               var osm = context.connection();
102654
102655               if (osm) {
102656                 var missing = _coords.filter(function (loc) {
102657                   return !osm.isDataLoaded(loc);
102658                 });
102659
102660                 if (missing.length) {
102661                   missing.forEach(function (loc) {
102662                     context.loadTileAtLoc(loc);
102663                   });
102664                   return true;
102665                 }
102666               }
102667
102668               return false;
102669             }
102670           };
102671
102672           operation.tooltip = function () {
102673             var disable = operation.disabled();
102674
102675             if (disable) {
102676               return _t('operations.disconnect.' + disable);
102677             }
102678
102679             return _t('operations.disconnect.description.' + _descriptionID);
102680           };
102681
102682           operation.annotation = function () {
102683             return _t('operations.disconnect.annotation.' + _annotationID);
102684           };
102685
102686           operation.id = 'disconnect';
102687           operation.keys = [_t('operations.disconnect.key')];
102688           operation.title = _t('operations.disconnect.title');
102689           operation.behavior = behaviorOperation(context).which(operation);
102690           return operation;
102691         }
102692
102693         function operationDowngrade(context, selectedIDs) {
102694           var _affectedFeatureCount = 0;
102695
102696           var _downgradeType = downgradeTypeForEntityIDs(selectedIDs);
102697
102698           var _multi = _affectedFeatureCount === 1 ? 'single' : 'multiple';
102699
102700           function downgradeTypeForEntityIDs(entityIds) {
102701             var downgradeType;
102702             _affectedFeatureCount = 0;
102703
102704             for (var i in entityIds) {
102705               var entityID = entityIds[i];
102706               var type = downgradeTypeForEntityID(entityID);
102707
102708               if (type) {
102709                 _affectedFeatureCount += 1;
102710
102711                 if (downgradeType && type !== downgradeType) {
102712                   if (downgradeType !== 'generic' && type !== 'generic') {
102713                     downgradeType = 'building_address';
102714                   } else {
102715                     downgradeType = 'generic';
102716                   }
102717                 } else {
102718                   downgradeType = type;
102719                 }
102720               }
102721             }
102722
102723             return downgradeType;
102724           }
102725
102726           function downgradeTypeForEntityID(entityID) {
102727             var graph = context.graph();
102728             var entity = graph.entity(entityID);
102729             var preset = _mainPresetIndex.match(entity, graph);
102730             if (!preset || preset.isFallback()) return null;
102731
102732             if (entity.type === 'node' && preset.id !== 'address' && Object.keys(entity.tags).some(function (key) {
102733               return key.match(/^addr:.{1,}/);
102734             })) {
102735               return 'address';
102736             }
102737
102738             var geometry = entity.geometry(graph);
102739
102740             if (geometry === 'area' && entity.tags.building && !preset.tags.building) {
102741               return 'building';
102742             }
102743
102744             if (geometry === 'vertex' && Object.keys(entity.tags).length) {
102745               return 'generic';
102746             }
102747
102748             return null;
102749           }
102750
102751           var buildingKeysToKeep = ['architect', 'building', 'height', 'layer', 'source', 'type', 'wheelchair'];
102752           var addressKeysToKeep = ['source'];
102753
102754           var operation = function operation() {
102755             context.perform(function (graph) {
102756               for (var i in selectedIDs) {
102757                 var entityID = selectedIDs[i];
102758                 var type = downgradeTypeForEntityID(entityID);
102759                 if (!type) continue;
102760                 var tags = Object.assign({}, graph.entity(entityID).tags); // shallow copy
102761
102762                 for (var key in tags) {
102763                   if (type === 'address' && addressKeysToKeep.indexOf(key) !== -1) continue;
102764
102765                   if (type === 'building') {
102766                     if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
102767                   }
102768
102769                   if (type !== 'generic') {
102770                     if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/)) continue;
102771                   }
102772
102773                   delete tags[key];
102774                 }
102775
102776                 graph = actionChangeTags(entityID, tags)(graph);
102777               }
102778
102779               return graph;
102780             }, operation.annotation());
102781             context.validator().validate(); // refresh the select mode to enable the delete operation
102782
102783             context.enter(modeSelect(context, selectedIDs));
102784           };
102785
102786           operation.available = function () {
102787             return _downgradeType;
102788           };
102789
102790           operation.disabled = function () {
102791             if (selectedIDs.some(hasWikidataTag)) {
102792               return 'has_wikidata_tag';
102793             }
102794
102795             return false;
102796
102797             function hasWikidataTag(id) {
102798               var entity = context.entity(id);
102799               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
102800             }
102801           };
102802
102803           operation.tooltip = function () {
102804             var disable = operation.disabled();
102805             return disable ? _t('operations.downgrade.' + disable + '.' + _multi) : _t('operations.downgrade.description.' + _downgradeType);
102806           };
102807
102808           operation.annotation = function () {
102809             var suffix;
102810
102811             if (_downgradeType === 'building_address') {
102812               suffix = 'generic';
102813             } else {
102814               suffix = _downgradeType;
102815             }
102816
102817             return _t('operations.downgrade.annotation.' + suffix, {
102818               n: _affectedFeatureCount
102819             });
102820           };
102821
102822           operation.id = 'downgrade';
102823           operation.keys = [uiCmd('⌫')];
102824           operation.title = _t('operations.downgrade.title');
102825           operation.behavior = behaviorOperation(context).which(operation);
102826           return operation;
102827         }
102828
102829         function operationExtract(context, selectedIDs) {
102830           var _amount = selectedIDs.length === 1 ? 'single' : 'multiple';
102831
102832           var _geometries = utilArrayUniq(selectedIDs.map(function (entityID) {
102833             return context.graph().hasEntity(entityID) && context.graph().geometry(entityID);
102834           }).filter(Boolean));
102835
102836           var _geometryID = _geometries.length === 1 ? _geometries[0] : 'feature';
102837
102838           var _extent;
102839
102840           var _actions = selectedIDs.map(function (entityID) {
102841             var graph = context.graph();
102842             var entity = graph.hasEntity(entityID);
102843             if (!entity || !entity.hasInterestingTags()) return null;
102844             if (entity.type === 'node' && graph.parentWays(entity).length === 0) return null;
102845
102846             if (entity.type !== 'node') {
102847               var preset = _mainPresetIndex.match(entity, graph); // only allow extraction from ways/relations if the preset supports points
102848
102849               if (preset.geometry.indexOf('point') === -1) return null;
102850             }
102851
102852             _extent = _extent ? _extent.extend(entity.extent(graph)) : entity.extent(graph);
102853             return actionExtract(entityID, context.projection);
102854           }).filter(Boolean);
102855
102856           var operation = function operation() {
102857             var combinedAction = function combinedAction(graph) {
102858               _actions.forEach(function (action) {
102859                 graph = action(graph);
102860               });
102861
102862               return graph;
102863             };
102864
102865             context.perform(combinedAction, operation.annotation()); // do the extract
102866
102867             var extractedNodeIDs = _actions.map(function (action) {
102868               return action.getExtractedNodeID();
102869             });
102870
102871             context.enter(modeSelect(context, extractedNodeIDs));
102872           };
102873
102874           operation.available = function () {
102875             return _actions.length && selectedIDs.length === _actions.length;
102876           };
102877
102878           operation.disabled = function () {
102879             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
102880               return 'too_large';
102881             } else if (selectedIDs.some(function (entityID) {
102882               return context.graph().geometry(entityID) === 'vertex' && context.hasHiddenConnections(entityID);
102883             })) {
102884               return 'connected_to_hidden';
102885             }
102886
102887             return false;
102888           };
102889
102890           operation.tooltip = function () {
102891             var disableReason = operation.disabled();
102892
102893             if (disableReason) {
102894               return _t('operations.extract.' + disableReason + '.' + _amount);
102895             } else {
102896               return _t('operations.extract.description.' + _geometryID + '.' + _amount);
102897             }
102898           };
102899
102900           operation.annotation = function () {
102901             return _t('operations.extract.annotation', {
102902               n: selectedIDs.length
102903             });
102904           };
102905
102906           operation.id = 'extract';
102907           operation.keys = [_t('operations.extract.key')];
102908           operation.title = _t('operations.extract.title');
102909           operation.behavior = behaviorOperation(context).which(operation);
102910           return operation;
102911         }
102912
102913         function operationMerge(context, selectedIDs) {
102914           var _action = getAction();
102915
102916           function getAction() {
102917             // prefer a non-disabled action first
102918             var join = actionJoin(selectedIDs);
102919             if (!join.disabled(context.graph())) return join;
102920             var merge = actionMerge(selectedIDs);
102921             if (!merge.disabled(context.graph())) return merge;
102922             var mergePolygon = actionMergePolygon(selectedIDs);
102923             if (!mergePolygon.disabled(context.graph())) return mergePolygon;
102924             var mergeNodes = actionMergeNodes(selectedIDs);
102925             if (!mergeNodes.disabled(context.graph())) return mergeNodes; // otherwise prefer an action with an interesting disabled reason
102926
102927             if (join.disabled(context.graph()) !== 'not_eligible') return join;
102928             if (merge.disabled(context.graph()) !== 'not_eligible') return merge;
102929             if (mergePolygon.disabled(context.graph()) !== 'not_eligible') return mergePolygon;
102930             return mergeNodes;
102931           }
102932
102933           var operation = function operation() {
102934             if (operation.disabled()) return;
102935             context.perform(_action, operation.annotation());
102936             context.validator().validate();
102937             var resultIDs = selectedIDs.filter(context.hasEntity);
102938
102939             if (resultIDs.length > 1) {
102940               var interestingIDs = resultIDs.filter(function (id) {
102941                 return context.entity(id).hasInterestingTags();
102942               });
102943               if (interestingIDs.length) resultIDs = interestingIDs;
102944             }
102945
102946             context.enter(modeSelect(context, resultIDs));
102947           };
102948
102949           operation.available = function () {
102950             return selectedIDs.length >= 2;
102951           };
102952
102953           operation.disabled = function () {
102954             var actionDisabled = _action.disabled(context.graph());
102955
102956             if (actionDisabled) return actionDisabled;
102957             var osm = context.connection();
102958
102959             if (osm && _action.resultingWayNodesLength && _action.resultingWayNodesLength(context.graph()) > osm.maxWayNodes()) {
102960               return 'too_many_vertices';
102961             }
102962
102963             return false;
102964           };
102965
102966           operation.tooltip = function () {
102967             var disabled = operation.disabled();
102968
102969             if (disabled) {
102970               if (disabled === 'restriction') {
102971                 return _t('operations.merge.restriction', {
102972                   relation: _mainPresetIndex.item('type/restriction').name()
102973                 });
102974               }
102975
102976               return _t('operations.merge.' + disabled);
102977             }
102978
102979             return _t('operations.merge.description');
102980           };
102981
102982           operation.annotation = function () {
102983             return _t('operations.merge.annotation', {
102984               n: selectedIDs.length
102985             });
102986           };
102987
102988           operation.id = 'merge';
102989           operation.keys = [_t('operations.merge.key')];
102990           operation.title = _t('operations.merge.title');
102991           operation.behavior = behaviorOperation(context).which(operation);
102992           return operation;
102993         }
102994
102995         function operationPaste(context) {
102996           var _pastePoint;
102997
102998           var operation = function operation() {
102999             if (!_pastePoint) return;
103000             var oldIDs = context.copyIDs();
103001             if (!oldIDs.length) return;
103002             var projection = context.projection;
103003             var extent = geoExtent();
103004             var oldGraph = context.copyGraph();
103005             var newIDs = [];
103006             var action = actionCopyEntities(oldIDs, oldGraph);
103007             context.perform(action);
103008             var copies = action.copies();
103009             var originals = new Set();
103010             Object.values(copies).forEach(function (entity) {
103011               originals.add(entity.id);
103012             });
103013
103014             for (var id in copies) {
103015               var oldEntity = oldGraph.entity(id);
103016               var newEntity = copies[id];
103017
103018               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
103019
103020
103021               var parents = context.graph().parentWays(newEntity);
103022               var parentCopied = parents.some(function (parent) {
103023                 return originals.has(parent.id);
103024               });
103025
103026               if (!parentCopied) {
103027                 newIDs.push(newEntity.id);
103028               }
103029             } // Use the location of the copy operation to offset the paste location,
103030             // or else use the center of the pasted extent
103031
103032
103033             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
103034             var delta = geoVecSubtract(_pastePoint, copyPoint); // Move the pasted objects to be anchored at the paste location
103035
103036             context.replace(actionMove(newIDs, delta, projection), operation.annotation());
103037             context.enter(modeSelect(context, newIDs));
103038           };
103039
103040           operation.point = function (val) {
103041             _pastePoint = val;
103042             return operation;
103043           };
103044
103045           operation.available = function () {
103046             return context.mode().id === 'browse';
103047           };
103048
103049           operation.disabled = function () {
103050             return !context.copyIDs().length;
103051           };
103052
103053           operation.tooltip = function () {
103054             var oldGraph = context.copyGraph();
103055             var ids = context.copyIDs();
103056
103057             if (!ids.length) {
103058               return _t('operations.paste.nothing_copied');
103059             }
103060
103061             return _t('operations.paste.description', {
103062               feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph),
103063               n: ids.length
103064             });
103065           };
103066
103067           operation.annotation = function () {
103068             var ids = context.copyIDs();
103069             return _t('operations.paste.annotation', {
103070               n: ids.length
103071             });
103072           };
103073
103074           operation.id = 'paste';
103075           operation.keys = [uiCmd('⌘V')];
103076           operation.title = _t('operations.paste.title');
103077           return operation;
103078         }
103079
103080         function operationReverse(context, selectedIDs) {
103081           var operation = function operation() {
103082             context.perform(function combinedReverseAction(graph) {
103083               actions().forEach(function (action) {
103084                 graph = action(graph);
103085               });
103086               return graph;
103087             }, operation.annotation());
103088             context.validator().validate();
103089           };
103090
103091           function actions(situation) {
103092             return selectedIDs.map(function (entityID) {
103093               var entity = context.hasEntity(entityID);
103094               if (!entity) return null;
103095
103096               if (situation === 'toolbar') {
103097                 if (entity.type === 'way' && !entity.isOneWay() && !entity.isSided()) return null;
103098               }
103099
103100               var geometry = entity.geometry(context.graph());
103101               if (entity.type !== 'node' && geometry !== 'line') return null;
103102               var action = actionReverse(entityID);
103103               if (action.disabled(context.graph())) return null;
103104               return action;
103105             }).filter(Boolean);
103106           }
103107
103108           function reverseTypeID() {
103109             var acts = actions();
103110             var nodeActionCount = acts.filter(function (act) {
103111               var entity = context.hasEntity(act.entityID());
103112               return entity && entity.type === 'node';
103113             }).length;
103114             if (nodeActionCount === 0) return 'line';
103115             if (nodeActionCount === acts.length) return 'point';
103116             return 'feature';
103117           }
103118
103119           operation.available = function (situation) {
103120             return actions(situation).length > 0;
103121           };
103122
103123           operation.disabled = function () {
103124             return false;
103125           };
103126
103127           operation.tooltip = function () {
103128             return _t('operations.reverse.description.' + reverseTypeID());
103129           };
103130
103131           operation.annotation = function () {
103132             var acts = actions();
103133             return _t('operations.reverse.annotation.' + reverseTypeID(), {
103134               n: acts.length
103135             });
103136           };
103137
103138           operation.id = 'reverse';
103139           operation.keys = [_t('operations.reverse.key')];
103140           operation.title = _t('operations.reverse.title');
103141           operation.behavior = behaviorOperation(context).which(operation);
103142           return operation;
103143         }
103144
103145         function operationSplit(context, selectedIDs) {
103146           var _vertexIds = selectedIDs.filter(function (id) {
103147             return context.graph().geometry(id) === 'vertex';
103148           });
103149
103150           var _selectedWayIds = selectedIDs.filter(function (id) {
103151             var entity = context.graph().hasEntity(id);
103152             return entity && entity.type === 'way';
103153           });
103154
103155           var _isAvailable = _vertexIds.length > 0 && _vertexIds.length + _selectedWayIds.length === selectedIDs.length;
103156
103157           var _action = actionSplit(_vertexIds);
103158
103159           var _ways = [];
103160           var _geometry = 'feature';
103161           var _waysAmount = 'single';
103162
103163           var _nodesAmount = _vertexIds.length === 1 ? 'single' : 'multiple';
103164
103165           if (_isAvailable) {
103166             if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
103167             _ways = _action.ways(context.graph());
103168             var geometries = {};
103169
103170             _ways.forEach(function (way) {
103171               geometries[way.geometry(context.graph())] = true;
103172             });
103173
103174             if (Object.keys(geometries).length === 1) {
103175               _geometry = Object.keys(geometries)[0];
103176             }
103177
103178             _waysAmount = _ways.length === 1 ? 'single' : 'multiple';
103179           }
103180
103181           var operation = function operation() {
103182             var difference = context.perform(_action, operation.annotation()); // select both the nodes and the ways so the mapper can immediately disconnect them if desired
103183
103184             var idsToSelect = _vertexIds.concat(difference.extantIDs().filter(function (id) {
103185               // filter out relations that may have had member additions
103186               return context.entity(id).type === 'way';
103187             }));
103188
103189             context.enter(modeSelect(context, idsToSelect));
103190           };
103191
103192           operation.relatedEntityIds = function () {
103193             return _selectedWayIds.length ? [] : _ways.map(function (way) {
103194               return way.id;
103195             });
103196           };
103197
103198           operation.available = function () {
103199             return _isAvailable;
103200           };
103201
103202           operation.disabled = function () {
103203             var reason = _action.disabled(context.graph());
103204
103205             if (reason) {
103206               return reason;
103207             } else if (selectedIDs.some(context.hasHiddenConnections)) {
103208               return 'connected_to_hidden';
103209             }
103210
103211             return false;
103212           };
103213
103214           operation.tooltip = function () {
103215             var disable = operation.disabled();
103216             if (disable) return _t('operations.split.' + disable);
103217             return _t('operations.split.description.' + _geometry + '.' + _waysAmount + '.' + _nodesAmount + '_node');
103218           };
103219
103220           operation.annotation = function () {
103221             return _t('operations.split.annotation.' + _geometry, {
103222               n: _ways.length
103223             });
103224           };
103225
103226           operation.id = 'split';
103227           operation.keys = [_t('operations.split.key')];
103228           operation.title = _t('operations.split.title');
103229           operation.behavior = behaviorOperation(context).which(operation);
103230           return operation;
103231         }
103232
103233         function operationStraighten(context, selectedIDs) {
103234           var _wayIDs = selectedIDs.filter(function (id) {
103235             return id.charAt(0) === 'w';
103236           });
103237
103238           var _nodeIDs = selectedIDs.filter(function (id) {
103239             return id.charAt(0) === 'n';
103240           });
103241
103242           var _amount = (_wayIDs.length ? _wayIDs : _nodeIDs).length === 1 ? 'single' : 'multiple';
103243
103244           var _nodes = utilGetAllNodes(selectedIDs, context.graph());
103245
103246           var _coords = _nodes.map(function (n) {
103247             return n.loc;
103248           });
103249
103250           var _extent = utilTotalExtent(selectedIDs, context.graph());
103251
103252           var _action = chooseAction();
103253
103254           var _geometry;
103255
103256           function chooseAction() {
103257             // straighten selected nodes
103258             if (_wayIDs.length === 0 && _nodeIDs.length > 2) {
103259               _geometry = 'point';
103260               return actionStraightenNodes(_nodeIDs, context.projection); // straighten selected ways (possibly between range of 2 selected nodes)
103261             } else if (_wayIDs.length > 0 && (_nodeIDs.length === 0 || _nodeIDs.length === 2)) {
103262               var startNodeIDs = [];
103263               var endNodeIDs = [];
103264
103265               for (var i = 0; i < selectedIDs.length; i++) {
103266                 var entity = context.entity(selectedIDs[i]);
103267
103268                 if (entity.type === 'node') {
103269                   continue;
103270                 } else if (entity.type !== 'way' || entity.isClosed()) {
103271                   return null; // exit early, can't straighten these
103272                 }
103273
103274                 startNodeIDs.push(entity.first());
103275                 endNodeIDs.push(entity.last());
103276               } // Remove duplicate end/startNodeIDs (duplicate nodes cannot be at the line end)
103277
103278
103279               startNodeIDs = startNodeIDs.filter(function (n) {
103280                 return startNodeIDs.indexOf(n) === startNodeIDs.lastIndexOf(n);
103281               });
103282               endNodeIDs = endNodeIDs.filter(function (n) {
103283                 return endNodeIDs.indexOf(n) === endNodeIDs.lastIndexOf(n);
103284               }); // Ensure all ways are connected (i.e. only 2 unique endpoints/startpoints)
103285
103286               if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2) return null; // Ensure path contains at least 3 unique nodes
103287
103288               var wayNodeIDs = utilGetAllNodes(_wayIDs, context.graph()).map(function (node) {
103289                 return node.id;
103290               });
103291               if (wayNodeIDs.length <= 2) return null; // If range of 2 selected nodes is supplied, ensure nodes lie on the selected path
103292
103293               if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1)) return null;
103294
103295               if (_nodeIDs.length) {
103296                 // If we're only straightenting between two points, we only need that extent visible
103297                 _extent = utilTotalExtent(_nodeIDs, context.graph());
103298               }
103299
103300               _geometry = 'line';
103301               return actionStraightenWay(selectedIDs, context.projection);
103302             }
103303
103304             return null;
103305           }
103306
103307           function operation() {
103308             if (!_action) return;
103309             context.perform(_action, operation.annotation());
103310             window.setTimeout(function () {
103311               context.validator().validate();
103312             }, 300); // after any transition
103313           }
103314
103315           operation.available = function () {
103316             return Boolean(_action);
103317           };
103318
103319           operation.disabled = function () {
103320             var reason = _action.disabled(context.graph());
103321
103322             if (reason) {
103323               return reason;
103324             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
103325               return 'too_large';
103326             } else if (someMissing()) {
103327               return 'not_downloaded';
103328             } else if (selectedIDs.some(context.hasHiddenConnections)) {
103329               return 'connected_to_hidden';
103330             }
103331
103332             return false;
103333
103334             function someMissing() {
103335               if (context.inIntro()) return false;
103336               var osm = context.connection();
103337
103338               if (osm) {
103339                 var missing = _coords.filter(function (loc) {
103340                   return !osm.isDataLoaded(loc);
103341                 });
103342
103343                 if (missing.length) {
103344                   missing.forEach(function (loc) {
103345                     context.loadTileAtLoc(loc);
103346                   });
103347                   return true;
103348                 }
103349               }
103350
103351               return false;
103352             }
103353           };
103354
103355           operation.tooltip = function () {
103356             var disable = operation.disabled();
103357             return disable ? _t('operations.straighten.' + disable + '.' + _amount) : _t('operations.straighten.description.' + _geometry + (_wayIDs.length === 1 ? '' : 's'));
103358           };
103359
103360           operation.annotation = function () {
103361             return _t('operations.straighten.annotation.' + _geometry, {
103362               n: _wayIDs.length ? _wayIDs.length : _nodeIDs.length
103363             });
103364           };
103365
103366           operation.id = 'straighten';
103367           operation.keys = [_t('operations.straighten.key')];
103368           operation.title = _t('operations.straighten.title');
103369           operation.behavior = behaviorOperation(context).which(operation);
103370           return operation;
103371         }
103372
103373         var Operations = /*#__PURE__*/Object.freeze({
103374                 __proto__: null,
103375                 operationCircularize: operationCircularize,
103376                 operationContinue: operationContinue,
103377                 operationCopy: operationCopy,
103378                 operationDelete: operationDelete,
103379                 operationDisconnect: operationDisconnect,
103380                 operationDowngrade: operationDowngrade,
103381                 operationExtract: operationExtract,
103382                 operationMerge: operationMerge,
103383                 operationMove: operationMove,
103384                 operationOrthogonalize: operationOrthogonalize,
103385                 operationPaste: operationPaste,
103386                 operationReflectShort: operationReflectShort,
103387                 operationReflectLong: operationReflectLong,
103388                 operationReverse: operationReverse,
103389                 operationRotate: operationRotate,
103390                 operationSplit: operationSplit,
103391                 operationStraighten: operationStraighten
103392         });
103393
103394         function modeSelect(context, selectedIDs) {
103395           var mode = {
103396             id: 'select',
103397             button: 'browse'
103398           };
103399           var keybinding = utilKeybinding('select');
103400
103401           var _breatheBehavior = behaviorBreathe();
103402
103403           var _modeDragNode = modeDragNode(context);
103404
103405           var _selectBehavior;
103406
103407           var _behaviors = [];
103408           var _operations = [];
103409           var _newFeature = false;
103410           var _follow = false; // `_focusedParentWayId` is used when we visit a vertex with multiple
103411           // parents, and we want to remember which parent line we started on.
103412
103413           var _focusedParentWayId;
103414
103415           var _focusedVertexIds;
103416
103417           function singular() {
103418             if (selectedIDs && selectedIDs.length === 1) {
103419               return context.hasEntity(selectedIDs[0]);
103420             }
103421           }
103422
103423           function selectedEntities() {
103424             return selectedIDs.map(function (id) {
103425               return context.hasEntity(id);
103426             }).filter(Boolean);
103427           }
103428
103429           function checkSelectedIDs() {
103430             var ids = [];
103431
103432             if (Array.isArray(selectedIDs)) {
103433               ids = selectedIDs.filter(function (id) {
103434                 return context.hasEntity(id);
103435               });
103436             }
103437
103438             if (!ids.length) {
103439               context.enter(modeBrowse(context));
103440               return false;
103441             } else if (selectedIDs.length > 1 && ids.length === 1 || selectedIDs.length === 1 && ids.length > 1) {
103442               // switch between single- and multi-select UI
103443               context.enter(modeSelect(context, ids));
103444               return false;
103445             }
103446
103447             selectedIDs = ids;
103448             return true;
103449           } // find the parent ways for nextVertex, previousVertex, and selectParent
103450
103451
103452           function parentWaysIdsOfSelection(onlyCommonParents) {
103453             var graph = context.graph();
103454             var parents = [];
103455
103456             for (var i = 0; i < selectedIDs.length; i++) {
103457               var entity = context.hasEntity(selectedIDs[i]);
103458
103459               if (!entity || entity.geometry(graph) !== 'vertex') {
103460                 return []; // selection includes some non-vertices
103461               }
103462
103463               var currParents = graph.parentWays(entity).map(function (w) {
103464                 return w.id;
103465               });
103466
103467               if (!parents.length) {
103468                 parents = currParents;
103469                 continue;
103470               }
103471
103472               parents = (onlyCommonParents ? utilArrayIntersection : utilArrayUnion)(parents, currParents);
103473
103474               if (!parents.length) {
103475                 return [];
103476               }
103477             }
103478
103479             return parents;
103480           } // find the child nodes for selected ways
103481
103482
103483           function childNodeIdsOfSelection(onlyCommon) {
103484             var graph = context.graph();
103485             var childs = [];
103486
103487             for (var i = 0; i < selectedIDs.length; i++) {
103488               var entity = context.hasEntity(selectedIDs[i]);
103489
103490               if (!entity || !['area', 'line'].includes(entity.geometry(graph))) {
103491                 return []; // selection includes non-area/non-line
103492               }
103493
103494               var currChilds = graph.childNodes(entity).map(function (node) {
103495                 return node.id;
103496               });
103497
103498               if (!childs.length) {
103499                 childs = currChilds;
103500                 continue;
103501               }
103502
103503               childs = (onlyCommon ? utilArrayIntersection : utilArrayUnion)(childs, currChilds);
103504
103505               if (!childs.length) {
103506                 return [];
103507               }
103508             }
103509
103510             return childs;
103511           }
103512
103513           function checkFocusedParent() {
103514             if (_focusedParentWayId) {
103515               var parents = parentWaysIdsOfSelection(true);
103516               if (parents.indexOf(_focusedParentWayId) === -1) _focusedParentWayId = null;
103517             }
103518           }
103519
103520           function parentWayIdForVertexNavigation() {
103521             var parentIds = parentWaysIdsOfSelection(true);
103522
103523             if (_focusedParentWayId && parentIds.indexOf(_focusedParentWayId) !== -1) {
103524               // prefer the previously seen parent
103525               return _focusedParentWayId;
103526             }
103527
103528             return parentIds.length ? parentIds[0] : null;
103529           }
103530
103531           mode.selectedIDs = function (val) {
103532             if (!arguments.length) return selectedIDs;
103533             selectedIDs = val;
103534             return mode;
103535           };
103536
103537           mode.zoomToSelected = function () {
103538             context.map().zoomToEase(selectedEntities());
103539           };
103540
103541           mode.newFeature = function (val) {
103542             if (!arguments.length) return _newFeature;
103543             _newFeature = val;
103544             return mode;
103545           };
103546
103547           mode.selectBehavior = function (val) {
103548             if (!arguments.length) return _selectBehavior;
103549             _selectBehavior = val;
103550             return mode;
103551           };
103552
103553           mode.follow = function (val) {
103554             if (!arguments.length) return _follow;
103555             _follow = val;
103556             return mode;
103557           };
103558
103559           function loadOperations() {
103560             _operations.forEach(function (operation) {
103561               if (operation.behavior) {
103562                 context.uninstall(operation.behavior);
103563               }
103564             });
103565
103566             _operations = Object.values(Operations).map(function (o) {
103567               return o(context, selectedIDs);
103568             }).filter(function (o) {
103569               return o.id !== 'delete' && o.id !== 'downgrade' && o.id !== 'copy';
103570             }).concat([// group copy/downgrade/delete operation together at the end of the list
103571             operationCopy(context, selectedIDs), operationDowngrade(context, selectedIDs), operationDelete(context, selectedIDs)]).filter(function (operation) {
103572               return operation.available();
103573             });
103574
103575             _operations.forEach(function (operation) {
103576               if (operation.behavior) {
103577                 context.install(operation.behavior);
103578               }
103579             }); // remove any displayed menu
103580
103581
103582             context.ui().closeEditMenu();
103583           }
103584
103585           mode.operations = function () {
103586             return _operations;
103587           };
103588
103589           mode.enter = function () {
103590             if (!checkSelectedIDs()) return;
103591             context.features().forceVisible(selectedIDs);
103592
103593             _modeDragNode.restoreSelectedIDs(selectedIDs);
103594
103595             loadOperations();
103596
103597             if (!_behaviors.length) {
103598               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
103599               _behaviors = [behaviorPaste(context), _breatheBehavior, behaviorHover(context).on('hover', context.ui().sidebar.hoverModeSelect), _selectBehavior, behaviorLasso(context), _modeDragNode.behavior, modeDragNote(context).behavior];
103600             }
103601
103602             _behaviors.forEach(context.install);
103603
103604             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on(['[', 'pgup'], previousVertex).on([']', 'pgdown'], nextVertex).on(['{', uiCmd('⌘['), 'home'], firstVertex).on(['}', uiCmd('⌘]'), 'end'], lastVertex).on(uiCmd('⇧←'), nudgeSelection([-10, 0])).on(uiCmd('⇧↑'), nudgeSelection([0, -10])).on(uiCmd('⇧→'), nudgeSelection([10, 0])).on(uiCmd('⇧↓'), nudgeSelection([0, 10])).on(uiCmd('⇧⌥←'), nudgeSelection([-100, 0])).on(uiCmd('⇧⌥↑'), nudgeSelection([0, -100])).on(uiCmd('⇧⌥→'), nudgeSelection([100, 0])).on(uiCmd('⇧⌥↓'), nudgeSelection([0, 100])).on(utilKeybinding.plusKeys.map(function (key) {
103605               return uiCmd('⇧' + key);
103606             }), scaleSelection(1.05)).on(utilKeybinding.plusKeys.map(function (key) {
103607               return uiCmd('⇧⌥' + key);
103608             }), scaleSelection(Math.pow(1.05, 5))).on(utilKeybinding.minusKeys.map(function (key) {
103609               return uiCmd('⇧' + key);
103610             }), scaleSelection(1 / 1.05)).on(utilKeybinding.minusKeys.map(function (key) {
103611               return uiCmd('⇧⌥' + key);
103612             }), scaleSelection(1 / Math.pow(1.05, 5))).on(['\\', 'pause'], focusNextParent).on(uiCmd('⌘↑'), selectParent).on(uiCmd('⌘↓'), selectChild).on('⎋', esc, true);
103613             select(document).call(keybinding);
103614             context.ui().sidebar.select(selectedIDs, _newFeature);
103615             context.history().on('change.select', function () {
103616               loadOperations(); // reselect after change in case relation members were removed or added
103617
103618               selectElements();
103619             }).on('undone.select', checkSelectedIDs).on('redone.select', checkSelectedIDs);
103620             context.map().on('drawn.select', selectElements).on('crossEditableZoom.select', function () {
103621               selectElements();
103622
103623               _breatheBehavior.restartIfNeeded(context.surface());
103624             });
103625             context.map().doubleUpHandler().on('doubleUp.modeSelect', didDoubleUp);
103626             selectElements();
103627
103628             if (_follow) {
103629               var extent = geoExtent();
103630               var graph = context.graph();
103631               selectedIDs.forEach(function (id) {
103632                 var entity = context.entity(id);
103633
103634                 extent._extend(entity.extent(graph));
103635               });
103636               var loc = extent.center();
103637               context.map().centerEase(loc); // we could enter the mode multiple times, so reset follow for next time
103638
103639               _follow = false;
103640             }
103641
103642             function nudgeSelection(delta) {
103643               return function () {
103644                 // prevent nudging during low zoom selection
103645                 if (!context.map().withinEditableZoom()) return;
103646                 var moveOp = operationMove(context, selectedIDs);
103647
103648                 if (moveOp.disabled()) {
103649                   context.ui().flash.duration(4000).iconName('#iD-operation-' + moveOp.id).iconClass('operation disabled').label(moveOp.tooltip)();
103650                 } else {
103651                   context.perform(actionMove(selectedIDs, delta, context.projection), moveOp.annotation());
103652                   context.validator().validate();
103653                 }
103654               };
103655             }
103656
103657             function scaleSelection(factor) {
103658               return function () {
103659                 // prevent scaling during low zoom selection
103660                 if (!context.map().withinEditableZoom()) return;
103661                 var nodes = utilGetAllNodes(selectedIDs, context.graph());
103662                 var isUp = factor > 1; // can only scale if multiple nodes are selected
103663
103664                 if (nodes.length <= 1) return;
103665                 var extent = utilTotalExtent(selectedIDs, context.graph()); // These disabled checks would normally be handled by an operation
103666                 // object, but we don't want an actual scale operation at this point.
103667
103668                 function scalingDisabled() {
103669                   if (tooSmall()) {
103670                     return 'too_small';
103671                   } else if (extent.percentContainedIn(context.map().extent()) < 0.8) {
103672                     return 'too_large';
103673                   } else if (someMissing() || selectedIDs.some(incompleteRelation)) {
103674                     return 'not_downloaded';
103675                   } else if (selectedIDs.some(context.hasHiddenConnections)) {
103676                     return 'connected_to_hidden';
103677                   }
103678
103679                   return false;
103680
103681                   function tooSmall() {
103682                     if (isUp) return false;
103683                     var dLon = Math.abs(extent[1][0] - extent[0][0]);
103684                     var dLat = Math.abs(extent[1][1] - extent[0][1]);
103685                     return dLon < geoMetersToLon(1, extent[1][1]) && dLat < geoMetersToLat(1);
103686                   }
103687
103688                   function someMissing() {
103689                     if (context.inIntro()) return false;
103690                     var osm = context.connection();
103691
103692                     if (osm) {
103693                       var missing = nodes.filter(function (n) {
103694                         return !osm.isDataLoaded(n.loc);
103695                       });
103696
103697                       if (missing.length) {
103698                         missing.forEach(function (loc) {
103699                           context.loadTileAtLoc(loc);
103700                         });
103701                         return true;
103702                       }
103703                     }
103704
103705                     return false;
103706                   }
103707
103708                   function incompleteRelation(id) {
103709                     var entity = context.entity(id);
103710                     return entity.type === 'relation' && !entity.isComplete(context.graph());
103711                   }
103712                 }
103713
103714                 var disabled = scalingDisabled();
103715
103716                 if (disabled) {
103717                   var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
103718                   context.ui().flash.duration(4000).iconName('#iD-icon-no').iconClass('operation disabled').label(_t('operations.scale.' + disabled + '.' + multi))();
103719                 } else {
103720                   var pivot = context.projection(extent.center());
103721                   var annotation = _t('operations.scale.annotation.' + (isUp ? 'up' : 'down') + '.feature', {
103722                     n: selectedIDs.length
103723                   });
103724                   context.perform(actionScale(selectedIDs, pivot, factor, context.projection), annotation);
103725                   context.validator().validate();
103726                 }
103727               };
103728             }
103729
103730             function didDoubleUp(d3_event, loc) {
103731               if (!context.map().withinEditableZoom()) return;
103732               var target = select(d3_event.target);
103733               var datum = target.datum();
103734               var entity = datum && datum.properties && datum.properties.entity;
103735               if (!entity) return;
103736
103737               if (entity instanceof osmWay && target.classed('target')) {
103738                 var choice = geoChooseEdge(context.graph().childNodes(entity), loc, context.projection);
103739                 var prev = entity.nodes[choice.index - 1];
103740                 var next = entity.nodes[choice.index];
103741                 context.perform(actionAddMidpoint({
103742                   loc: choice.loc,
103743                   edge: [prev, next]
103744                 }, osmNode()), _t('operations.add.annotation.vertex'));
103745               } else if (entity.type === 'midpoint') {
103746                 context.perform(actionAddMidpoint({
103747                   loc: entity.loc,
103748                   edge: entity.edge
103749                 }, osmNode()), _t('operations.add.annotation.vertex'));
103750               }
103751             }
103752
103753             function selectElements() {
103754               if (!checkSelectedIDs()) return;
103755               var surface = context.surface();
103756               surface.selectAll('.selected-member').classed('selected-member', false);
103757               surface.selectAll('.selected').classed('selected', false);
103758               surface.selectAll('.related').classed('related', false); // reload `_focusedParentWayId` based on the current selection
103759
103760               checkFocusedParent();
103761
103762               if (_focusedParentWayId) {
103763                 surface.selectAll(utilEntitySelector([_focusedParentWayId])).classed('related', true);
103764               }
103765
103766               if (context.map().withinEditableZoom()) {
103767                 // Apply selection styling if not in wide selection
103768                 surface.selectAll(utilDeepMemberSelector(selectedIDs, context.graph(), true
103769                 /* skipMultipolgonMembers */
103770                 )).classed('selected-member', true);
103771                 surface.selectAll(utilEntityOrDeepMemberSelector(selectedIDs, context.graph())).classed('selected', true);
103772               }
103773             }
103774
103775             function esc() {
103776               if (context.container().select('.combobox').size()) return;
103777               context.enter(modeBrowse(context));
103778             }
103779
103780             function firstVertex(d3_event) {
103781               d3_event.preventDefault();
103782               var entity = singular();
103783               var parentId = parentWayIdForVertexNavigation();
103784               var way;
103785
103786               if (entity && entity.type === 'way') {
103787                 way = entity;
103788               } else if (parentId) {
103789                 way = context.entity(parentId);
103790               }
103791
103792               _focusedParentWayId = way && way.id;
103793
103794               if (way) {
103795                 context.enter(mode.selectedIDs([way.first()]).follow(true));
103796               }
103797             }
103798
103799             function lastVertex(d3_event) {
103800               d3_event.preventDefault();
103801               var entity = singular();
103802               var parentId = parentWayIdForVertexNavigation();
103803               var way;
103804
103805               if (entity && entity.type === 'way') {
103806                 way = entity;
103807               } else if (parentId) {
103808                 way = context.entity(parentId);
103809               }
103810
103811               _focusedParentWayId = way && way.id;
103812
103813               if (way) {
103814                 context.enter(mode.selectedIDs([way.last()]).follow(true));
103815               }
103816             }
103817
103818             function previousVertex(d3_event) {
103819               d3_event.preventDefault();
103820               var parentId = parentWayIdForVertexNavigation();
103821               _focusedParentWayId = parentId;
103822               if (!parentId) return;
103823               var way = context.entity(parentId);
103824               var length = way.nodes.length;
103825               var curr = way.nodes.indexOf(selectedIDs[0]);
103826               var index = -1;
103827
103828               if (curr > 0) {
103829                 index = curr - 1;
103830               } else if (way.isClosed()) {
103831                 index = length - 2;
103832               }
103833
103834               if (index !== -1) {
103835                 context.enter(mode.selectedIDs([way.nodes[index]]).follow(true));
103836               }
103837             }
103838
103839             function nextVertex(d3_event) {
103840               d3_event.preventDefault();
103841               var parentId = parentWayIdForVertexNavigation();
103842               _focusedParentWayId = parentId;
103843               if (!parentId) return;
103844               var way = context.entity(parentId);
103845               var length = way.nodes.length;
103846               var curr = way.nodes.indexOf(selectedIDs[0]);
103847               var index = -1;
103848
103849               if (curr < length - 1) {
103850                 index = curr + 1;
103851               } else if (way.isClosed()) {
103852                 index = 0;
103853               }
103854
103855               if (index !== -1) {
103856                 context.enter(mode.selectedIDs([way.nodes[index]]).follow(true));
103857               }
103858             }
103859
103860             function focusNextParent(d3_event) {
103861               d3_event.preventDefault();
103862               var parents = parentWaysIdsOfSelection(true);
103863               if (!parents || parents.length < 2) return;
103864               var index = parents.indexOf(_focusedParentWayId);
103865
103866               if (index < 0 || index > parents.length - 2) {
103867                 _focusedParentWayId = parents[0];
103868               } else {
103869                 _focusedParentWayId = parents[index + 1];
103870               }
103871
103872               var surface = context.surface();
103873               surface.selectAll('.related').classed('related', false);
103874
103875               if (_focusedParentWayId) {
103876                 surface.selectAll(utilEntitySelector([_focusedParentWayId])).classed('related', true);
103877               }
103878             }
103879
103880             function selectParent(d3_event) {
103881               d3_event.preventDefault();
103882               var currentSelectedIds = mode.selectedIDs();
103883               var parentIds = _focusedParentWayId ? [_focusedParentWayId] : parentWaysIdsOfSelection(false);
103884               if (!parentIds.length) return;
103885               context.enter(mode.selectedIDs(parentIds)); // set this after re-entering the selection since we normally want it cleared on exit
103886
103887               _focusedVertexIds = currentSelectedIds;
103888             }
103889
103890             function selectChild(d3_event) {
103891               d3_event.preventDefault();
103892               var currentSelectedIds = mode.selectedIDs();
103893               var childIds = _focusedVertexIds ? _focusedVertexIds.filter(function (id) {
103894                 return context.hasEntity(id);
103895               }) : childNodeIdsOfSelection(true);
103896               if (!childIds || !childIds.length) return;
103897               if (currentSelectedIds.length === 1) _focusedParentWayId = currentSelectedIds[0];
103898               context.enter(mode.selectedIDs(childIds));
103899             }
103900           };
103901
103902           mode.exit = function () {
103903             // we could enter the mode multiple times but it's only new the first time
103904             _newFeature = false;
103905             _focusedVertexIds = null;
103906
103907             _operations.forEach(function (operation) {
103908               if (operation.behavior) {
103909                 context.uninstall(operation.behavior);
103910               }
103911             });
103912
103913             _operations = [];
103914
103915             _behaviors.forEach(context.uninstall);
103916
103917             select(document).call(keybinding.unbind);
103918             context.ui().closeEditMenu();
103919             context.history().on('change.select', null).on('undone.select', null).on('redone.select', null);
103920             var surface = context.surface();
103921             surface.selectAll('.selected-member').classed('selected-member', false);
103922             surface.selectAll('.selected').classed('selected', false);
103923             surface.selectAll('.highlighted').classed('highlighted', false);
103924             surface.selectAll('.related').classed('related', false);
103925             context.map().on('drawn.select', null);
103926             context.ui().sidebar.hide();
103927             context.features().forceVisible([]);
103928             var entity = singular();
103929
103930             if (_newFeature && entity && entity.type === 'relation' && // no tags
103931             Object.keys(entity.tags).length === 0 && // no parent relations
103932             context.graph().parentRelations(entity).length === 0 && ( // no members or one member with no role
103933             entity.members.length === 0 || entity.members.length === 1 && !entity.members[0].role)) {
103934               // the user added this relation but didn't edit it at all, so just delete it
103935               var deleteAction = actionDeleteRelation(entity.id, true
103936               /* don't delete untagged members */
103937               );
103938               context.perform(deleteAction, _t('operations.delete.annotation.relation'));
103939             }
103940           };
103941
103942           return mode;
103943         }
103944
103945         function uiLasso(context) {
103946           var group, polygon;
103947           lasso.coordinates = [];
103948
103949           function lasso(selection) {
103950             context.container().classed('lasso', true);
103951             group = selection.append('g').attr('class', 'lasso hide');
103952             polygon = group.append('path').attr('class', 'lasso-path');
103953             group.call(uiToggle(true));
103954           }
103955
103956           function draw() {
103957             if (polygon) {
103958               polygon.data([lasso.coordinates]).attr('d', function (d) {
103959                 return 'M' + d.join(' L') + ' Z';
103960               });
103961             }
103962           }
103963
103964           lasso.extent = function () {
103965             return lasso.coordinates.reduce(function (extent, point) {
103966               return extent.extend(geoExtent(point));
103967             }, geoExtent());
103968           };
103969
103970           lasso.p = function (_) {
103971             if (!arguments.length) return lasso;
103972             lasso.coordinates.push(_);
103973             draw();
103974             return lasso;
103975           };
103976
103977           lasso.close = function () {
103978             if (group) {
103979               group.call(uiToggle(false, function () {
103980                 select(this).remove();
103981               }));
103982             }
103983
103984             context.container().classed('lasso', false);
103985           };
103986
103987           return lasso;
103988         }
103989
103990         function behaviorLasso(context) {
103991           // use pointer events on supported platforms; fallback to mouse events
103992           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
103993
103994           var behavior = function behavior(selection) {
103995             var lasso;
103996
103997             function pointerdown(d3_event) {
103998               var button = 0; // left
103999
104000               if (d3_event.button === button && d3_event.shiftKey === true) {
104001                 lasso = null;
104002                 select(window).on(_pointerPrefix + 'move.lasso', pointermove).on(_pointerPrefix + 'up.lasso', pointerup);
104003                 d3_event.stopPropagation();
104004               }
104005             }
104006
104007             function pointermove() {
104008               if (!lasso) {
104009                 lasso = uiLasso(context);
104010                 context.surface().call(lasso);
104011               }
104012
104013               lasso.p(context.map().mouse());
104014             }
104015
104016             function normalize(a, b) {
104017               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])]];
104018             }
104019
104020             function lassoed() {
104021               if (!lasso) return [];
104022               var graph = context.graph();
104023               var limitToNodes;
104024
104025               if (context.map().editableDataEnabled(true
104026               /* skipZoomCheck */
104027               ) && context.map().isInWideSelection()) {
104028                 // only select from the visible nodes
104029                 limitToNodes = new Set(utilGetAllNodes(context.selectedIDs(), graph));
104030               } else if (!context.map().editableDataEnabled()) {
104031                 return [];
104032               }
104033
104034               var bounds = lasso.extent().map(context.projection.invert);
104035               var extent = geoExtent(normalize(bounds[0], bounds[1]));
104036               var intersects = context.history().intersects(extent).filter(function (entity) {
104037                 return entity.type === 'node' && (!limitToNodes || limitToNodes.has(entity)) && geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) && !context.features().isHidden(entity, graph, entity.geometry(graph));
104038               }); // sort the lassoed nodes as best we can
104039
104040               intersects.sort(function (node1, node2) {
104041                 var parents1 = graph.parentWays(node1);
104042                 var parents2 = graph.parentWays(node2);
104043
104044                 if (parents1.length && parents2.length) {
104045                   // both nodes are vertices
104046                   var sharedParents = utilArrayIntersection(parents1, parents2);
104047
104048                   if (sharedParents.length) {
104049                     var sharedParentNodes = sharedParents[0].nodes; // vertices are members of the same way; sort them in their listed order
104050
104051                     return sharedParentNodes.indexOf(node1.id) - sharedParentNodes.indexOf(node2.id);
104052                   } else {
104053                     // vertices do not share a way; group them by their respective parent ways
104054                     return parseFloat(parents1[0].id.slice(1)) - parseFloat(parents2[0].id.slice(1));
104055                   }
104056                 } else if (parents1.length || parents2.length) {
104057                   // only one node is a vertex; sort standalone points before vertices
104058                   return parents1.length - parents2.length;
104059                 } // both nodes are standalone points; sort left to right
104060
104061
104062                 return node1.loc[0] - node2.loc[0];
104063               });
104064               return intersects.map(function (entity) {
104065                 return entity.id;
104066               });
104067             }
104068
104069             function pointerup() {
104070               select(window).on(_pointerPrefix + 'move.lasso', null).on(_pointerPrefix + 'up.lasso', null);
104071               if (!lasso) return;
104072               var ids = lassoed();
104073               lasso.close();
104074
104075               if (ids.length) {
104076                 context.enter(modeSelect(context, ids));
104077               }
104078             }
104079
104080             selection.on(_pointerPrefix + 'down.lasso', pointerdown);
104081           };
104082
104083           behavior.off = function (selection) {
104084             selection.on(_pointerPrefix + 'down.lasso', null);
104085           };
104086
104087           return behavior;
104088         }
104089
104090         function modeBrowse(context) {
104091           var mode = {
104092             button: 'browse',
104093             id: 'browse',
104094             title: _t('modes.browse.title'),
104095             description: _t('modes.browse.description')
104096           };
104097           var sidebar;
104098
104099           var _selectBehavior;
104100
104101           var _behaviors = [];
104102
104103           mode.selectBehavior = function (val) {
104104             if (!arguments.length) return _selectBehavior;
104105             _selectBehavior = val;
104106             return mode;
104107           };
104108
104109           mode.enter = function () {
104110             if (!_behaviors.length) {
104111               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
104112               _behaviors = [behaviorPaste(context), behaviorHover(context).on('hover', context.ui().sidebar.hover), _selectBehavior, behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
104113             }
104114
104115             _behaviors.forEach(context.install); // Get focus on the body.
104116
104117
104118             if (document.activeElement && document.activeElement.blur) {
104119               document.activeElement.blur();
104120             }
104121
104122             if (sidebar) {
104123               context.ui().sidebar.show(sidebar);
104124             } else {
104125               context.ui().sidebar.select(null);
104126             }
104127           };
104128
104129           mode.exit = function () {
104130             context.ui().sidebar.hover.cancel();
104131
104132             _behaviors.forEach(context.uninstall);
104133
104134             if (sidebar) {
104135               context.ui().sidebar.hide();
104136             }
104137           };
104138
104139           mode.sidebar = function (_) {
104140             if (!arguments.length) return sidebar;
104141             sidebar = _;
104142             return mode;
104143           };
104144
104145           mode.operations = function () {
104146             return [operationPaste(context)];
104147           };
104148
104149           return mode;
104150         }
104151
104152         function behaviorAddWay(context) {
104153           var dispatch = dispatch$8('start', 'startFromWay', 'startFromNode');
104154           var draw = behaviorDraw(context);
104155
104156           function behavior(surface) {
104157             draw.on('click', function () {
104158               dispatch.apply('start', this, arguments);
104159             }).on('clickWay', function () {
104160               dispatch.apply('startFromWay', this, arguments);
104161             }).on('clickNode', function () {
104162               dispatch.apply('startFromNode', this, arguments);
104163             }).on('cancel', behavior.cancel).on('finish', behavior.cancel);
104164             context.map().dblclickZoomEnable(false);
104165             surface.call(draw);
104166           }
104167
104168           behavior.off = function (surface) {
104169             surface.call(draw.off);
104170           };
104171
104172           behavior.cancel = function () {
104173             window.setTimeout(function () {
104174               context.map().dblclickZoomEnable(true);
104175             }, 1000);
104176             context.enter(modeBrowse(context));
104177           };
104178
104179           return utilRebind(behavior, dispatch, 'on');
104180         }
104181
104182         function behaviorHash(context) {
104183           // cached window.location.hash
104184           var _cachedHash = null; // allowable latitude range
104185
104186           var _latitudeLimit = 90 - 1e-8;
104187
104188           function computedHashParameters() {
104189             var map = context.map();
104190             var center = map.center();
104191             var zoom = map.zoom();
104192             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
104193             var oldParams = utilObjectOmit(utilStringQs(window.location.hash), ['comment', 'source', 'hashtags', 'walkthrough']);
104194             var newParams = {};
104195             delete oldParams.id;
104196             var selected = context.selectedIDs().filter(function (id) {
104197               return context.hasEntity(id);
104198             });
104199
104200             if (selected.length) {
104201               newParams.id = selected.join(',');
104202             }
104203
104204             newParams.map = zoom.toFixed(2) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
104205             return Object.assign(oldParams, newParams);
104206           }
104207
104208           function computedHash() {
104209             return '#' + utilQsString(computedHashParameters(), true);
104210           }
104211
104212           function computedTitle(includeChangeCount) {
104213             var baseTitle = context.documentTitleBase() || 'iD';
104214             var contextual;
104215             var changeCount;
104216             var titleID;
104217             var selected = context.selectedIDs().filter(function (id) {
104218               return context.hasEntity(id);
104219             });
104220
104221             if (selected.length) {
104222               var firstLabel = utilDisplayLabel(context.entity(selected[0]), context.graph());
104223
104224               if (selected.length > 1) {
104225                 contextual = _t('title.labeled_and_more', {
104226                   labeled: firstLabel,
104227                   count: selected.length - 1
104228                 });
104229               } else {
104230                 contextual = firstLabel;
104231               }
104232
104233               titleID = 'context';
104234             }
104235
104236             if (includeChangeCount) {
104237               changeCount = context.history().difference().summary().length;
104238
104239               if (changeCount > 0) {
104240                 titleID = contextual ? 'changes_context' : 'changes';
104241               }
104242             }
104243
104244             if (titleID) {
104245               return _t('title.format.' + titleID, {
104246                 changes: changeCount,
104247                 base: baseTitle,
104248                 context: contextual
104249               });
104250             }
104251
104252             return baseTitle;
104253           }
104254
104255           function updateTitle(includeChangeCount) {
104256             if (!context.setsDocumentTitle()) return;
104257             var newTitle = computedTitle(includeChangeCount);
104258
104259             if (document.title !== newTitle) {
104260               document.title = newTitle;
104261             }
104262           }
104263
104264           function updateHashIfNeeded() {
104265             if (context.inIntro()) return;
104266             var latestHash = computedHash();
104267
104268             if (_cachedHash !== latestHash) {
104269               _cachedHash = latestHash; // Update the URL hash without affecting the browser navigation stack,
104270               // though unavoidably creating a browser history entry
104271
104272               window.history.replaceState(null, computedTitle(false
104273               /* includeChangeCount */
104274               ), latestHash); // set the title we want displayed for the browser tab/window
104275
104276               updateTitle(true
104277               /* includeChangeCount */
104278               );
104279             }
104280           }
104281
104282           var _throttledUpdate = throttle(updateHashIfNeeded, 500);
104283
104284           var _throttledUpdateTitle = throttle(function () {
104285             updateTitle(true
104286             /* includeChangeCount */
104287             );
104288           }, 500);
104289
104290           function hashchange() {
104291             // ignore spurious hashchange events
104292             if (window.location.hash === _cachedHash) return;
104293             _cachedHash = window.location.hash;
104294             var q = utilStringQs(_cachedHash);
104295             var mapArgs = (q.map || '').split('/').map(Number);
104296
104297             if (mapArgs.length < 3 || mapArgs.some(isNaN)) {
104298               // replace bogus hash
104299               updateHashIfNeeded();
104300             } else {
104301               // don't update if the new hash already reflects the state of iD
104302               if (_cachedHash === computedHash()) return;
104303               var mode = context.mode();
104304               context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
104305
104306               if (q.id && mode) {
104307                 var ids = q.id.split(',').filter(function (id) {
104308                   return context.hasEntity(id);
104309                 });
104310
104311                 if (ids.length && (mode.id === 'browse' || mode.id === 'select' && !utilArrayIdentical(mode.selectedIDs(), ids))) {
104312                   context.enter(modeSelect(context, ids));
104313                   return;
104314                 }
104315               }
104316
104317               var center = context.map().center();
104318               var dist = geoSphericalDistance(center, [mapArgs[2], mapArgs[1]]);
104319               var maxdist = 500; // Don't allow the hash location to change too much while drawing
104320               // This can happen if the user accidentally hit the back button.  #3996
104321
104322               if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
104323                 context.enter(modeBrowse(context));
104324                 return;
104325               }
104326             }
104327           }
104328
104329           function behavior() {
104330             context.map().on('move.behaviorHash', _throttledUpdate);
104331             context.history().on('change.behaviorHash', _throttledUpdateTitle);
104332             context.on('enter.behaviorHash', _throttledUpdate);
104333             select(window).on('hashchange.behaviorHash', hashchange);
104334
104335             if (window.location.hash) {
104336               var q = utilStringQs(window.location.hash);
104337
104338               if (q.id) {
104339                 //if (!context.history().hasRestorableChanges()) {
104340                 // targeting specific features: download, select, and zoom to them
104341                 context.zoomToEntity(q.id.split(',')[0], !q.map); //}
104342               }
104343
104344               if (q.walkthrough === 'true') {
104345                 behavior.startWalkthrough = true;
104346               }
104347
104348               if (q.map) {
104349                 behavior.hadHash = true;
104350               }
104351
104352               hashchange();
104353               updateTitle(false);
104354             }
104355           }
104356
104357           behavior.off = function () {
104358             _throttledUpdate.cancel();
104359
104360             _throttledUpdateTitle.cancel();
104361
104362             context.map().on('move.behaviorHash', null);
104363             context.on('enter.behaviorHash', null);
104364             select(window).on('hashchange.behaviorHash', null);
104365             window.location.hash = '';
104366           };
104367
104368           return behavior;
104369         }
104370
104371         // This is only done in testing because of the performance penalty.
104372
104373         var debug = false; // Reexport just what our tests use, see #4379
104374         var d3 = {
104375           dispatch: dispatch$8,
104376           geoMercator: mercator,
104377           geoProjection: projection,
104378           polygonArea: d3_polygonArea,
104379           polygonCentroid: d3_polygonCentroid,
104380           select: select,
104381           selectAll: selectAll,
104382           timerFlush: timerFlush
104383         };
104384
104385         var iD = /*#__PURE__*/Object.freeze({
104386                 __proto__: null,
104387                 debug: debug,
104388                 d3: d3,
104389                 actionAddEntity: actionAddEntity,
104390                 actionAddMember: actionAddMember,
104391                 actionAddMidpoint: actionAddMidpoint,
104392                 actionAddVertex: actionAddVertex,
104393                 actionChangeMember: actionChangeMember,
104394                 actionChangePreset: actionChangePreset,
104395                 actionChangeTags: actionChangeTags,
104396                 actionCircularize: actionCircularize,
104397                 actionConnect: actionConnect,
104398                 actionCopyEntities: actionCopyEntities,
104399                 actionDeleteMember: actionDeleteMember,
104400                 actionDeleteMultiple: actionDeleteMultiple,
104401                 actionDeleteNode: actionDeleteNode,
104402                 actionDeleteRelation: actionDeleteRelation,
104403                 actionDeleteWay: actionDeleteWay,
104404                 actionDiscardTags: actionDiscardTags,
104405                 actionDisconnect: actionDisconnect,
104406                 actionExtract: actionExtract,
104407                 actionJoin: actionJoin,
104408                 actionMerge: actionMerge,
104409                 actionMergeNodes: actionMergeNodes,
104410                 actionMergePolygon: actionMergePolygon,
104411                 actionMergeRemoteChanges: actionMergeRemoteChanges,
104412                 actionMove: actionMove,
104413                 actionMoveMember: actionMoveMember,
104414                 actionMoveNode: actionMoveNode,
104415                 actionNoop: actionNoop,
104416                 actionOrthogonalize: actionOrthogonalize,
104417                 actionRestrictTurn: actionRestrictTurn,
104418                 actionReverse: actionReverse,
104419                 actionRevert: actionRevert,
104420                 actionRotate: actionRotate,
104421                 actionScale: actionScale,
104422                 actionSplit: actionSplit,
104423                 actionStraightenNodes: actionStraightenNodes,
104424                 actionStraightenWay: actionStraightenWay,
104425                 actionUnrestrictTurn: actionUnrestrictTurn,
104426                 actionReflect: actionReflect,
104427                 actionUpgradeTags: actionUpgradeTags,
104428                 behaviorAddWay: behaviorAddWay,
104429                 behaviorBreathe: behaviorBreathe,
104430                 behaviorDrag: behaviorDrag,
104431                 behaviorDrawWay: behaviorDrawWay,
104432                 behaviorDraw: behaviorDraw,
104433                 behaviorEdit: behaviorEdit,
104434                 behaviorHash: behaviorHash,
104435                 behaviorHover: behaviorHover,
104436                 behaviorLasso: behaviorLasso,
104437                 behaviorOperation: behaviorOperation,
104438                 behaviorPaste: behaviorPaste,
104439                 behaviorSelect: behaviorSelect,
104440                 coreContext: coreContext,
104441                 coreFileFetcher: coreFileFetcher,
104442                 fileFetcher: _mainFileFetcher,
104443                 coreDifference: coreDifference,
104444                 coreGraph: coreGraph,
104445                 coreHistory: coreHistory,
104446                 coreLocalizer: coreLocalizer,
104447                 t: _t,
104448                 localizer: _mainLocalizer,
104449                 coreLocations: coreLocations,
104450                 locationManager: _mainLocations,
104451                 prefs: corePreferences,
104452                 coreTree: coreTree,
104453                 coreUploader: coreUploader,
104454                 coreValidator: coreValidator,
104455                 geoExtent: geoExtent,
104456                 geoLatToMeters: geoLatToMeters,
104457                 geoLonToMeters: geoLonToMeters,
104458                 geoMetersToLat: geoMetersToLat,
104459                 geoMetersToLon: geoMetersToLon,
104460                 geoMetersToOffset: geoMetersToOffset,
104461                 geoOffsetToMeters: geoOffsetToMeters,
104462                 geoScaleToZoom: geoScaleToZoom,
104463                 geoSphericalClosestNode: geoSphericalClosestNode,
104464                 geoSphericalDistance: geoSphericalDistance,
104465                 geoZoomToScale: geoZoomToScale,
104466                 geoAngle: geoAngle,
104467                 geoChooseEdge: geoChooseEdge,
104468                 geoEdgeEqual: geoEdgeEqual,
104469                 geoGetSmallestSurroundingRectangle: geoGetSmallestSurroundingRectangle,
104470                 geoHasLineIntersections: geoHasLineIntersections,
104471                 geoHasSelfIntersections: geoHasSelfIntersections,
104472                 geoRotate: geoRotate,
104473                 geoLineIntersection: geoLineIntersection,
104474                 geoPathHasIntersections: geoPathHasIntersections,
104475                 geoPathIntersections: geoPathIntersections,
104476                 geoPathLength: geoPathLength,
104477                 geoPointInPolygon: geoPointInPolygon,
104478                 geoPolygonContainsPolygon: geoPolygonContainsPolygon,
104479                 geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
104480                 geoViewportEdge: geoViewportEdge,
104481                 geoRawMercator: geoRawMercator,
104482                 geoVecAdd: geoVecAdd,
104483                 geoVecAngle: geoVecAngle,
104484                 geoVecCross: geoVecCross,
104485                 geoVecDot: geoVecDot,
104486                 geoVecEqual: geoVecEqual,
104487                 geoVecFloor: geoVecFloor,
104488                 geoVecInterp: geoVecInterp,
104489                 geoVecLength: geoVecLength,
104490                 geoVecLengthSquare: geoVecLengthSquare,
104491                 geoVecNormalize: geoVecNormalize,
104492                 geoVecNormalizedDot: geoVecNormalizedDot,
104493                 geoVecProject: geoVecProject,
104494                 geoVecSubtract: geoVecSubtract,
104495                 geoVecScale: geoVecScale,
104496                 geoOrthoNormalizedDotProduct: geoOrthoNormalizedDotProduct,
104497                 geoOrthoCalcScore: geoOrthoCalcScore,
104498                 geoOrthoMaxOffsetAngle: geoOrthoMaxOffsetAngle,
104499                 geoOrthoCanOrthogonalize: geoOrthoCanOrthogonalize,
104500                 modeAddArea: modeAddArea,
104501                 modeAddLine: modeAddLine,
104502                 modeAddPoint: modeAddPoint,
104503                 modeAddNote: modeAddNote,
104504                 modeBrowse: modeBrowse,
104505                 modeDragNode: modeDragNode,
104506                 modeDragNote: modeDragNote,
104507                 modeDrawArea: modeDrawArea,
104508                 modeDrawLine: modeDrawLine,
104509                 modeMove: modeMove,
104510                 modeRotate: modeRotate,
104511                 modeSave: modeSave,
104512                 modeSelect: modeSelect,
104513                 modeSelectData: modeSelectData,
104514                 modeSelectError: modeSelectError,
104515                 modeSelectNote: modeSelectNote,
104516                 operationCircularize: operationCircularize,
104517                 operationContinue: operationContinue,
104518                 operationCopy: operationCopy,
104519                 operationDelete: operationDelete,
104520                 operationDisconnect: operationDisconnect,
104521                 operationDowngrade: operationDowngrade,
104522                 operationExtract: operationExtract,
104523                 operationMerge: operationMerge,
104524                 operationMove: operationMove,
104525                 operationOrthogonalize: operationOrthogonalize,
104526                 operationPaste: operationPaste,
104527                 operationReflectShort: operationReflectShort,
104528                 operationReflectLong: operationReflectLong,
104529                 operationReverse: operationReverse,
104530                 operationRotate: operationRotate,
104531                 operationSplit: operationSplit,
104532                 operationStraighten: operationStraighten,
104533                 osmChangeset: osmChangeset,
104534                 osmEntity: osmEntity,
104535                 osmNode: osmNode,
104536                 osmNote: osmNote,
104537                 osmRelation: osmRelation,
104538                 osmWay: osmWay,
104539                 QAItem: QAItem,
104540                 osmIntersection: osmIntersection,
104541                 osmTurn: osmTurn,
104542                 osmInferRestriction: osmInferRestriction,
104543                 osmLanes: osmLanes,
104544                 osmOldMultipolygonOuterMemberOfRelation: osmOldMultipolygonOuterMemberOfRelation,
104545                 osmIsOldMultipolygonOuterMember: osmIsOldMultipolygonOuterMember,
104546                 osmOldMultipolygonOuterMember: osmOldMultipolygonOuterMember,
104547                 osmJoinWays: osmJoinWays,
104548                 get osmAreaKeys () { return osmAreaKeys; },
104549                 osmSetAreaKeys: osmSetAreaKeys,
104550                 osmTagSuggestingArea: osmTagSuggestingArea,
104551                 get osmPointTags () { return osmPointTags; },
104552                 osmSetPointTags: osmSetPointTags,
104553                 get osmVertexTags () { return osmVertexTags; },
104554                 osmSetVertexTags: osmSetVertexTags,
104555                 osmNodeGeometriesForTags: osmNodeGeometriesForTags,
104556                 osmOneWayTags: osmOneWayTags,
104557                 osmPavedTags: osmPavedTags,
104558                 osmIsInterestingTag: osmIsInterestingTag,
104559                 osmRoutableHighwayTagValues: osmRoutableHighwayTagValues,
104560                 osmFlowingWaterwayTagValues: osmFlowingWaterwayTagValues,
104561                 osmRailwayTrackTagValues: osmRailwayTrackTagValues,
104562                 presetCategory: presetCategory,
104563                 presetCollection: presetCollection,
104564                 presetField: presetField,
104565                 presetPreset: presetPreset,
104566                 presetManager: _mainPresetIndex,
104567                 presetIndex: presetIndex,
104568                 rendererBackgroundSource: rendererBackgroundSource,
104569                 rendererBackground: rendererBackground,
104570                 rendererFeatures: rendererFeatures,
104571                 rendererMap: rendererMap,
104572                 rendererPhotos: rendererPhotos,
104573                 rendererTileLayer: rendererTileLayer,
104574                 services: services,
104575                 serviceKeepRight: serviceKeepRight,
104576                 serviceImproveOSM: serviceImproveOSM,
104577                 serviceOsmose: serviceOsmose,
104578                 serviceMapillary: serviceMapillary,
104579                 serviceMapRules: serviceMapRules,
104580                 serviceNominatim: serviceNominatim,
104581                 serviceNsi: serviceNsi,
104582                 serviceOpenstreetcam: serviceOpenstreetcam,
104583                 serviceOsm: serviceOsm,
104584                 serviceOsmWikibase: serviceOsmWikibase,
104585                 serviceStreetside: serviceStreetside,
104586                 serviceTaginfo: serviceTaginfo,
104587                 serviceVectorTile: serviceVectorTile,
104588                 serviceWikidata: serviceWikidata,
104589                 serviceWikipedia: serviceWikipedia,
104590                 svgAreas: svgAreas,
104591                 svgData: svgData,
104592                 svgDebug: svgDebug,
104593                 svgDefs: svgDefs,
104594                 svgKeepRight: svgKeepRight,
104595                 svgIcon: svgIcon,
104596                 svgGeolocate: svgGeolocate,
104597                 svgLabels: svgLabels,
104598                 svgLayers: svgLayers,
104599                 svgLines: svgLines,
104600                 svgMapillaryImages: svgMapillaryImages,
104601                 svgMapillarySigns: svgMapillarySigns,
104602                 svgMidpoints: svgMidpoints,
104603                 svgNotes: svgNotes,
104604                 svgMarkerSegments: svgMarkerSegments,
104605                 svgOpenstreetcamImages: svgOpenstreetcamImages,
104606                 svgOsm: svgOsm,
104607                 svgPassiveVertex: svgPassiveVertex,
104608                 svgPath: svgPath,
104609                 svgPointTransform: svgPointTransform,
104610                 svgPoints: svgPoints,
104611                 svgRelationMemberTags: svgRelationMemberTags,
104612                 svgSegmentWay: svgSegmentWay,
104613                 svgStreetside: svgStreetside,
104614                 svgTagClasses: svgTagClasses,
104615                 svgTagPattern: svgTagPattern,
104616                 svgTouch: svgTouch,
104617                 svgTurns: svgTurns,
104618                 svgVertices: svgVertices,
104619                 uiFieldDefaultCheck: uiFieldCheck,
104620                 uiFieldOnewayCheck: uiFieldCheck,
104621                 uiFieldCheck: uiFieldCheck,
104622                 uiFieldManyCombo: uiFieldCombo,
104623                 uiFieldMultiCombo: uiFieldCombo,
104624                 uiFieldNetworkCombo: uiFieldCombo,
104625                 uiFieldSemiCombo: uiFieldCombo,
104626                 uiFieldTypeCombo: uiFieldCombo,
104627                 uiFieldCombo: uiFieldCombo,
104628                 uiFieldUrl: uiFieldText,
104629                 uiFieldIdentifier: uiFieldText,
104630                 uiFieldNumber: uiFieldText,
104631                 uiFieldTel: uiFieldText,
104632                 uiFieldEmail: uiFieldText,
104633                 uiFieldText: uiFieldText,
104634                 uiFieldAccess: uiFieldAccess,
104635                 uiFieldAddress: uiFieldAddress,
104636                 uiFieldCycleway: uiFieldCycleway,
104637                 uiFieldLanes: uiFieldLanes,
104638                 uiFieldLocalized: uiFieldLocalized,
104639                 uiFieldRoadspeed: uiFieldRoadspeed,
104640                 uiFieldStructureRadio: uiFieldRadio,
104641                 uiFieldRadio: uiFieldRadio,
104642                 uiFieldRestrictions: uiFieldRestrictions,
104643                 uiFieldTextarea: uiFieldTextarea,
104644                 uiFieldWikidata: uiFieldWikidata,
104645                 uiFieldWikipedia: uiFieldWikipedia,
104646                 uiFields: uiFields,
104647                 uiIntro: uiIntro,
104648                 uiPanelBackground: uiPanelBackground,
104649                 uiPanelHistory: uiPanelHistory,
104650                 uiPanelLocation: uiPanelLocation,
104651                 uiPanelMeasurement: uiPanelMeasurement,
104652                 uiInfoPanels: uiInfoPanels,
104653                 uiPaneBackground: uiPaneBackground,
104654                 uiPaneHelp: uiPaneHelp,
104655                 uiPaneIssues: uiPaneIssues,
104656                 uiPaneMapData: uiPaneMapData,
104657                 uiPanePreferences: uiPanePreferences,
104658                 uiSectionBackgroundDisplayOptions: uiSectionBackgroundDisplayOptions,
104659                 uiSectionBackgroundList: uiSectionBackgroundList,
104660                 uiSectionBackgroundOffset: uiSectionBackgroundOffset,
104661                 uiSectionChanges: uiSectionChanges,
104662                 uiSectionDataLayers: uiSectionDataLayers,
104663                 uiSectionEntityIssues: uiSectionEntityIssues,
104664                 uiSectionFeatureType: uiSectionFeatureType,
104665                 uiSectionMapFeatures: uiSectionMapFeatures,
104666                 uiSectionMapStyleOptions: uiSectionMapStyleOptions,
104667                 uiSectionOverlayList: uiSectionOverlayList,
104668                 uiSectionPhotoOverlays: uiSectionPhotoOverlays,
104669                 uiSectionPresetFields: uiSectionPresetFields,
104670                 uiSectionPrivacy: uiSectionPrivacy,
104671                 uiSectionRawMemberEditor: uiSectionRawMemberEditor,
104672                 uiSectionRawMembershipEditor: uiSectionRawMembershipEditor,
104673                 uiSectionRawTagEditor: uiSectionRawTagEditor,
104674                 uiSectionSelectionList: uiSectionSelectionList,
104675                 uiSectionValidationIssues: uiSectionValidationIssues,
104676                 uiSectionValidationOptions: uiSectionValidationOptions,
104677                 uiSectionValidationRules: uiSectionValidationRules,
104678                 uiSectionValidationStatus: uiSectionValidationStatus,
104679                 uiSettingsCustomBackground: uiSettingsCustomBackground,
104680                 uiSettingsCustomData: uiSettingsCustomData,
104681                 uiInit: uiInit,
104682                 uiAccount: uiAccount,
104683                 uiAttribution: uiAttribution,
104684                 uiChangesetEditor: uiChangesetEditor,
104685                 uiCmd: uiCmd,
104686                 uiCombobox: uiCombobox,
104687                 uiCommit: uiCommit,
104688                 uiCommitWarnings: uiCommitWarnings,
104689                 uiConfirm: uiConfirm,
104690                 uiConflicts: uiConflicts,
104691                 uiContributors: uiContributors,
104692                 uiCurtain: uiCurtain,
104693                 uiDataEditor: uiDataEditor,
104694                 uiDataHeader: uiDataHeader,
104695                 uiDisclosure: uiDisclosure,
104696                 uiEditMenu: uiEditMenu,
104697                 uiEntityEditor: uiEntityEditor,
104698                 uiFeatureInfo: uiFeatureInfo,
104699                 uiFeatureList: uiFeatureList,
104700                 uiField: uiField,
104701                 uiFieldHelp: uiFieldHelp,
104702                 uiFlash: uiFlash,
104703                 uiFormFields: uiFormFields,
104704                 uiFullScreen: uiFullScreen,
104705                 uiGeolocate: uiGeolocate,
104706                 uiImproveOsmComments: uiImproveOsmComments,
104707                 uiImproveOsmDetails: uiImproveOsmDetails,
104708                 uiImproveOsmEditor: uiImproveOsmEditor,
104709                 uiImproveOsmHeader: uiImproveOsmHeader,
104710                 uiInfo: uiInfo,
104711                 uiInspector: uiInspector,
104712                 uiIssuesInfo: uiIssuesInfo,
104713                 uiKeepRightDetails: uiKeepRightDetails,
104714                 uiKeepRightEditor: uiKeepRightEditor,
104715                 uiKeepRightHeader: uiKeepRightHeader,
104716                 uiLasso: uiLasso,
104717                 uiLoading: uiLoading,
104718                 uiMapInMap: uiMapInMap,
104719                 uiModal: uiModal,
104720                 uiNotice: uiNotice,
104721                 uiNoteComments: uiNoteComments,
104722                 uiNoteEditor: uiNoteEditor,
104723                 uiNoteHeader: uiNoteHeader,
104724                 uiNoteReport: uiNoteReport,
104725                 uiPopover: uiPopover,
104726                 uiPresetIcon: uiPresetIcon,
104727                 uiPresetList: uiPresetList,
104728                 uiRestore: uiRestore,
104729                 uiScale: uiScale,
104730                 uiSidebar: uiSidebar,
104731                 uiSourceSwitch: uiSourceSwitch,
104732                 uiSpinner: uiSpinner,
104733                 uiSplash: uiSplash,
104734                 uiStatus: uiStatus,
104735                 uiSuccess: uiSuccess,
104736                 uiTagReference: uiTagReference,
104737                 uiToggle: uiToggle,
104738                 uiTooltip: uiTooltip,
104739                 uiVersion: uiVersion,
104740                 uiViewOnOSM: uiViewOnOSM,
104741                 uiViewOnKeepRight: uiViewOnKeepRight,
104742                 uiZoom: uiZoom,
104743                 utilAesEncrypt: utilAesEncrypt,
104744                 utilAesDecrypt: utilAesDecrypt,
104745                 utilArrayChunk: utilArrayChunk,
104746                 utilArrayDifference: utilArrayDifference,
104747                 utilArrayFlatten: utilArrayFlatten,
104748                 utilArrayGroupBy: utilArrayGroupBy,
104749                 utilArrayIdentical: utilArrayIdentical,
104750                 utilArrayIntersection: utilArrayIntersection,
104751                 utilArrayUnion: utilArrayUnion,
104752                 utilArrayUniq: utilArrayUniq,
104753                 utilArrayUniqBy: utilArrayUniqBy,
104754                 utilAsyncMap: utilAsyncMap,
104755                 utilCleanTags: utilCleanTags,
104756                 utilCombinedTags: utilCombinedTags,
104757                 utilDeepMemberSelector: utilDeepMemberSelector,
104758                 utilDetect: utilDetect,
104759                 utilDisplayName: utilDisplayName,
104760                 utilDisplayNameForPath: utilDisplayNameForPath,
104761                 utilDisplayType: utilDisplayType,
104762                 utilDisplayLabel: utilDisplayLabel,
104763                 utilEntityRoot: utilEntityRoot,
104764                 utilEditDistance: utilEditDistance,
104765                 utilEntitySelector: utilEntitySelector,
104766                 utilEntityOrMemberSelector: utilEntityOrMemberSelector,
104767                 utilEntityOrDeepMemberSelector: utilEntityOrDeepMemberSelector,
104768                 utilFastMouse: utilFastMouse,
104769                 utilFetchJson: utilFetchJson,
104770                 utilFunctor: utilFunctor,
104771                 utilGetAllNodes: utilGetAllNodes,
104772                 utilGetSetValue: utilGetSetValue,
104773                 utilHashcode: utilHashcode,
104774                 utilHighlightEntities: utilHighlightEntities,
104775                 utilKeybinding: utilKeybinding,
104776                 utilNoAuto: utilNoAuto,
104777                 utilObjectOmit: utilObjectOmit,
104778                 utilPrefixCSSProperty: utilPrefixCSSProperty,
104779                 utilPrefixDOMProperty: utilPrefixDOMProperty,
104780                 utilQsString: utilQsString,
104781                 utilRebind: utilRebind,
104782                 utilSafeClassName: utilSafeClassName,
104783                 utilSetTransform: utilSetTransform,
104784                 utilSessionMutex: utilSessionMutex,
104785                 utilStringQs: utilStringQs,
104786                 utilTagDiff: utilTagDiff,
104787                 utilTagText: utilTagText,
104788                 utilTiler: utilTiler,
104789                 utilTotalExtent: utilTotalExtent,
104790                 utilTriggerEvent: utilTriggerEvent,
104791                 utilUnicodeCharsCount: utilUnicodeCharsCount,
104792                 utilUnicodeCharsTruncated: utilUnicodeCharsTruncated,
104793                 utilUniqueDomId: utilUniqueDomId,
104794                 utilWrap: utilWrap,
104795                 validationAlmostJunction: validationAlmostJunction,
104796                 validationCloseNodes: validationCloseNodes,
104797                 validationCrossingWays: validationCrossingWays,
104798                 validationDisconnectedWay: validationDisconnectedWay,
104799                 validationFormatting: validationFormatting,
104800                 validationHelpRequest: validationHelpRequest,
104801                 validationImpossibleOneway: validationImpossibleOneway,
104802                 validationIncompatibleSource: validationIncompatibleSource,
104803                 validationMaprules: validationMaprules,
104804                 validationMismatchedGeometry: validationMismatchedGeometry,
104805                 validationMissingRole: validationMissingRole,
104806                 validationMissingTag: validationMissingTag,
104807                 validationOutdatedTags: validationOutdatedTags,
104808                 validationPrivateData: validationPrivateData,
104809                 validationSuspiciousName: validationSuspiciousName,
104810                 validationUnsquareWay: validationUnsquareWay
104811         });
104812
104813         window.requestIdleCallback = window.requestIdleCallback || function (cb) {
104814           var start = Date.now();
104815           return window.requestAnimationFrame(function () {
104816             cb({
104817               didTimeout: false,
104818               timeRemaining: function timeRemaining() {
104819                 return Math.max(0, 50 - (Date.now() - start));
104820               }
104821             });
104822           });
104823         };
104824
104825         window.cancelIdleCallback = window.cancelIdleCallback || function (id) {
104826           window.cancelAnimationFrame(id);
104827         };
104828         window.iD = iD;
104829
104830 }());